12

抽象静的メソッド/フィールド自体がない理由について、すでにいくつかのSOの質問がありますが、次の擬似コードを実装する方法について疑問に思っています:

class Animal {
    abstract static int getNumberOfLegs(); // not possible
}

class Chicken inherits Animal {
    static int getNumberOfLegs() { return 2; }


class Dog inherits Animal {
    static int getNumberOfLegs() { return 4; }

Animalここに問題があります:継承するすべてのクラスにメソッドが含まれていることを確認したいと仮定しますgetNumberOfLegs()(つまり、抽象クラスにすべての子クラスに共通のいくつかのメソッドを実装させたいことを除いて、ほとんどインターフェースのようです。したがって、純粋なインターフェースはそうではありませんここで働く)。getNumberOfLegs()明らかに静的メソッドである必要があります (完全な世界では鶏や犬を不自由にしていないと仮定すると、getNumberOfLegsインスタンスに依存しません)。

「抽象静的」メソッド/フィールドがないと、メソッドをクラスから除外することができ、Animal一部の子クラスにそのメソッドがないというリスクがあります。またはgetNumberOfLegs、インスタンス メソッドを作成することもできますが、その場合、動物の脚の数を調べるためにクラスをインスタンス化する必要があります (必須ではありませんが)。

通常、この状況をどのように実装しますか?


編集:ここで、これをどのように使用するかを示します。各動物の足の数が一意であると仮定すると (これはばかげていますが、とにかく...)、次のようになります。

Animal getModelAnimal(int numberOfLegs) {
   if (numberOfLegs == Chicken.getNumberOfLegs()) return new Chicken();
   else if (numberOfLegs == Dog.getNumberOfLegs()) return new Dog();
}
4

11 に答える 11

4

通常、この状況をどのように実装しますか?

通常の解決策は、問題のメソッドをインスタンス メソッドにすることです。

getNumberOfLegs()明らかに静的メソッドである必要があります (完璧な世界では、不自由なニワトリやイヌgetNumberOfLegsがいないと仮定すると、インスタンスに依存しません)。

それは明白ではありません!私たちは完璧な世界を目指してプログラムするわけではありません。現実の世界では、4 本足の動物が 1 本、2 本、または 3 本 (または 5 本) の足を持っていることがあります。

プログラムに動物のインスタンスではなく動物の定義が必要な場合は、そのためのクラスを作成しください。

class AnimalDefinition {
    public string getScientificName();
    public string getCommonName();
    public int    getNumberOfLegs();
    public bool   getIsAmphibious();
    // etc.
}

次に、プログラムの最初にそれらのコレクションを初期化します。理想的には、データベースまたは構成ファイルから、別のコード行を作成またはコンパイルせずに動物の定義を追加できます。(そして、はるかに少ないタイプでうまくいくことができます。)

于 2010-05-30T00:11:09.840 に答える
3

あなたの疑似コードは Java によく似ていたので、あなたが使っているのは Java だと思います。

「抽象メソッドにはインスタンスごとの実装が必要です。静的メソッドはクラス全体に関係します。抽象クラスの静的メソッドは、潜在的な実装ではなく、抽象クラスに属します。したがって、抽象静的メソッドを許可しても意味がありません。さらに、静的メソッドはオーバーライドできないため、やはり抽象静的メソッドは例外です。」

http://forums.sun.com/thread.jspa?threadID=597378から

Java インターフェイスで静的メソッドを定義できないのはなぜですか?も参照してください。

于 2010-05-29T23:05:34.390 に答える
3

これは本当に良い点であり、時にはabstract static本当に欠けています。getNumberLegs()しかし、最近はメモリが問題にならないので、 -メソッドをインスタンス メソッドとして実装することもできます。

静的抽象はナンセンスだと言うのは正しくありません。PHP では抽象静的メソッド (このを参照) が許可されており、あなたのシナリオは、状況によってはそれが役立つ可能性があることを示しています。

staticメソッドをオーバーライドできないと言うのも真実ではありません。finalメソッドはオーバーライドできません。Java や C# などの言語でstaticは、final. staticそのため、多くの人はそれが「上書き不可」に等しいと想定しています。

C# について話すと (コメントを読んだ後、C# を「話す」と仮定します)、ジェネリックと属性 (または Java のジェネリックと注釈) を使用することを検討できます。

public class Animal
{
   public static int GetNumberOfLegs<T>() where T : Animal
   {
     //Get T's custom attribute "NumberOfLegs" and return its value 
   }

   //EDIT: Added runtime-version of GetNumberOfLegs.
   public static int GetNumberOfLegs(Type t)
   {
     //Get t's custom attribute "NumberOfLegs" and return its value 

   }
}

[NumberOfLegs(4)]
public class Cat { ... };

これにより、インスタンス化せずに各タイプの脚の数を取得できます。[NumberOfLegs(x)]属性を示すことを忘れないでください。また、コンパイル時に型を知る必要があります (メソッドのジェネリック バージョンの場合)。

編集:オブジェクトGetNumberOfLegs()を渡すことができる-メソッドのランタイムバージョンを追加しました( Java用である必要があります)。この場合、実行時に型チェックを行う必要があります。つまり、オブジェクトによって表される型が継承されているかどうかを確認し、属性/注釈で渡された値を取得します。TypeClassTypeClassAnimal

使用法:

int numberOfLegs1 = Animal.GetNumberOfLegs<Cat>(); 
int numberOfLegs2 = Animal.GetNumberOfLegs(typeof(Cat)); //runtime version
于 2010-05-29T23:12:02.427 に答える
2

通常、この状況をどのように実装しますか?

Java 用語では、固定引数を取る抽象クラスでコンストラクターを宣言するだけです。各サブクラスはそれを呼び出す必要があり、それ以外の場合はコンパイルされません。

abstract class Animal {
    private int numberOfLegs;

    public Animal(int numberOfLegs) {
        this.numberOfLegs = numberOfLegs;
    }

    public int getNumberOfLegs() {
        return numberOfLegs;
    }
}

class Chicken extends Animal {
    public Chicken() {
        super(2);
    }
}

class Dog extends Animal {
    public Dog() {
        super(4);
    }
}

更新:あなたの更新に従って

編集:ここで、これをどのように使用するかを示します。各動物の足の数が一意であると仮定すると (これはばかげていますが、とにかく...)、次のようになります。

Animal getModelAnimal(int numberOfLegs) {
   if (numberOfLegs == Chicken.getNumberOfLegs()) return new Chicken();
   else if (numberOfLegs == Dog.getNumberOfLegs()) return new Dog();
}

これは確かにばかげています。これには、これらの具体的な動物のすべてが、抽象ファクトリ メソッドで事前にわかっている必要があります。新しい具象動物タイプが追加されるたびに、抽象ファクトリ メソッドを更新する必要があります。それでは、抽象工場のポイントは何ですか? あなたはすでにすべてを事前に知っていますか?いいえ、抽象ファクトリメソッドに完全修飾クラス名を識別子などとして使用させて、クラスパスからロードを試行できるようにします (まだ Java 用語で話しています)。

于 2010-05-29T23:22:18.670 に答える
0

abstract staticメソッドは、変数にインスタンスだけでなく実際の型を含めることができる言語でのみ意味があります。(Delphiはそのような言語の1つですが、c#はそうではなく、Javaでも実行できるとは思いません)。その理由は、コンパイル時に使用しているクラスが正確にわかっている場合(例のように)、メソッドを使用する理由はなく、各クラスのメソッドに同じ名前abstractを付けることができるからです。static使用している型がわからない可能性がある唯一の方法は、型を変数に割り当てることができるかどうかです。そうすれば、(クラスのインスタンスのように)それらを渡すことができ、突然すべてが実際に意味をなし、便利になります。

変数への型(および型のインスタンス)の割り当てをサポートするほとんどのコンパイラ/言語も、コンパイラマジックを介してサポートabstract staticvirtual abstractメソッドを管理していると思います。したがって、選択した言語で実際に役立つ場合は、サポートする必要があります。

于 2010-05-30T01:39:42.830 に答える
0

ここで見ることができるもう 1 つのアプローチは、抽象ファクトリを作成することです。これは c# です。レッグの数を知るために Chicken のインスタンスを作成する必要はありません。checken ファクトリ メソッドを呼び出すだけです

abstract class AnimalFactory
{
    public abstract Animal CreateAnimal();
    public abstract int GetLegs();

}
abstract class Animal
{

}
internal class Chicken : Animal
{

}
class CreateChicken : AnimalFactory
{
    public override Animal CreateAnimal()
    {
        return new Chicken();
    }
    public override int GetLegs()
    {
        return 2;
    }

}
于 2010-05-31T14:53:17.287 に答える
0

基本クラスにその実装で例外をスローさせることにより、メソッドが実装されていることを実行時にチェックすることができます。あまり価値はありませんが、何もないほうがいいかもしれません...

于 2010-05-30T01:08:08.187 に答える
0

これは興味深い質問です。私の意見では、「静的抽象」メソッドが必要になることはめったになく、常に適切な代替手段があります。

たとえば、提供したユースケースでは、ファクトリメソッドは具体的な動物クラスを名前でアドレス指定します。新しい動物クラスごとに、新しい特定のコードを追加する必要があります。したがって、「抽象的な」修飾は実際には必要ないようです。静的メソッド getNumberLegs() を提供する規則で十分です。

さらに一般的に言えば、abstract と static を組み合わせても (Java では) 意味がありません。なぜなら、abstractはポリモーフィズムを意味するのに対し、static呼び出しはまったくポリモーフィックではなく、コンパイル時に既知のクラスで機能するからです。

于 2010-05-29T23:52:32.757 に答える
0

抽象メソッドは、基本クラスを支援するために呼び出す場合に意味があります。あなたの例では、ポリモーフィズムをまったく利用していないことに注意してください。例では次のようになります。

  (Animal)Dog.getNumberOfLegs() //cast Dog to Animal first

とにかく、PHP はいわゆる「レイト スタティック バインディング」を実装しています。これはおそらくあなたが探しているものです。

http://php.net/manual/en/language.oop5.late-static-bindings.php

C++ では、タンプレートとコンパイル時のポリモーフィズムを使用して同様の機能を実現できます。

于 2010-05-30T01:23:44.707 に答える
0

しばらくの間、「抽象静的メソッド」が許可されていると仮定します。

次に、あなたのコードを使用して、これを追加します:

Animal modelAnimal;
int numLegs;

modelAnimal = this.getModelAnimal(4); // Got a dog

numLegs = modelAnimal.getNumberOfLegs();

DogオブジェクトであるmodelAnimalがDogクラスではなくAnimalクラスでgetNumberOfLegsを呼び出そうとすると、エラーが発生します。あなたが知っている静的メソッドのオーバーライドはありません。この状況を回避するために、設計者は抽象静的メソッドを含めていません。

于 2011-06-20T12:03:04.407 に答える
0

抽象静的メソッドを作成できたとしても、それをどのように使用しますか? 実装方法を考える前に、それをどのように使用するかを考えてください。実装は用途に合わせなければなりません。

于 2010-05-29T23:07:57.177 に答える