2

次のクラスを想定します。

public class Animal
{
}

public class Dog : Animal
{
     public void Bark()
     {
     }
}

public class Cat : Animal
{
     public void Meow()
     {
     }
}


Animal cat = Cat();
Animal dog = Dog();
PatternIamLookingFor.DoSomething(cat); // -> Call Meow
PatternIamLookingFor.DoSomething(dog); // -> Call Bark

これは可能ですか?MakeNoise() のようなメソッドを Animal 基底クラスに追加せずに?

私のアプリケーションには、AnimalFactory を実装して動物を返す CatFactory と DogFactory があります。工場でニャー/バークを呼び出すことはできず、動物を入手した後は呼び出すことができません。

4

5 に答える 5

2

インターフェイスを介して行うことができます。これは、 とほぼ同じですAnimal.MakeNoise()が、少し異なります。

public class Animal
{
}

public interface IAnimalNoises
{
    void MakeNoise();
}

public class Dog : Animal, IAnimalNoises
{
     IAnimalNoises.MakeNoise()
     {
         Bark();
     }

     public void Bark()
     {
     }
}

public class Cat : Animal, IAnimalNoises
{
     IAnimalNoises.MakeNoise()
     {
         Meow();
     }

     public void Meow()
     {
     }
}

public class PatternIamLookingFor
{
    public static void DoSomething(IAnimalNoises animal)
    {
        animal.MakeNoise();
    }
}

Animal cat = new Cat();
Animal dog = new Dog();
PatternIamLookingFor.DoSomething(cat); // -> Call Meow
PatternIamLookingFor.DoSomething(dog); // -> Call Bark

Cat cat2 = new Cat();
cat2.MakeNoise(); //Compiler error as it is not visible unless cast as a IAnimalNoises

変更できないレガシーコードを使用している場合、これが最良のオプションである場合がありますが、オプションがある場合は、コードをリファクタリングMakeNoise()し、各子クラスを呼び出して基本クラスを持っていることを強くお勧めします (またはインターフェイス) を定義します。

于 2013-09-30T20:11:42.643 に答える
2

コード例Animalでは、ポリモーフィックな動作はありません。つまり、基本クラスへの参照への同じメッセージが、実行されるさまざまな具体的な動作になります。

于 2013-09-30T20:02:41.110 に答える
2

上記のようなものを実装する方法はいくつか考えられます。

1. インターフェイスを使用する

元のソース コードを変更できる場合は、おそらくこれが最適なオプションです。実装が簡単で、保守も簡単です。

public interface IDoSomething
{
    void DoSomething();
}

public class Dog : Animal, IDoSomething
{
     public void Bark()
     {
     }

     void IDoSomething.DoSomething(){
         Bark();
     }
}

public class Cat : Animal, IDoSomething
{
     public void Meow()
     {
     }

     void IDoSomething.DoSomething(){
         Meow();
     }
}

2.アダプターを使用する

元のソース コードにアクセスできない場合は、アダプターが唯一の選択肢となる場合があります。これらを使用して、コードが Cat および Dog クラスにアクセスする方法を「同期」できます。元のオブジェクトであるかのようにアダプターを操作できますが、新しいコードのニーズにより適した変更されたインターフェイスを使用できます。親タイプに基づいて適切なアダプターを作成するためのファクトリーを作成するのはかなり簡単です。

public IDoSomething
{
    void DoSomething()
    {
    }
}

public DoSomethingFactory
{

    public static IDoSomething( Animal parent )
    {
        if ( typeof( parent ) is Dog )
            return new DoSomethingDog( parent as Dog );
        if ( typeof( parent ) is Cat )
            return new DoSomethingCat( parent as Cat );
        return null;
    }

}

public DoSomethingDog : Dog, IDoSomething
{
    Dog _parent;
    public DoSomethingDog( Dog parent )
    {
        _parent = parent;
    }

    public void DoSomething()
    {
        _parent.Bark();
    }
}

public DoSomethingCat : Cat, IDoSomething
{
    Cat _parent;
    public DoSomethingCat( Cat parent )
    {
        _parent = parent;
    }

    public void DoSomething()
    {
        _parent.Meow();
    }
}

これら 2 つの明白な実装とは別に、次のことを検討することをお勧めします。

  • デコレーターを使用して、クラスの機能を動的に強化します。(上記の「ラッパー」アプローチに似ていますが、クラス構造にもう少しきれいに焼き付けられています。)

  • クラスが動的に処理できる一連のCommandオブジェクトを実装します。

    cat.Do( new MakeNoiseCommand() ); // Handled as "meow"
    dog.Do( new MakeNoiseCommand() ); // Handled as "bark"
    
  • 動物のタイプなどに基づいてリクエストを転送するメディエーターに似たものを許可します。

    public class AnimalMediator
    {
        public void MakeNoise( Animal animal )
        {
            if ( typeof( animal ) is Dog ) (animal as Dog).Bark();
            else if ( typeof( animal ) is Cat ) (animal as Cat).Meow();
        }
    }
    
于 2013-09-30T20:12:56.863 に答える
2

これは可能ですか?MakeNoise() のようなメソッドを Animal 基底クラスに追加せずに?

呼び出すメソッドのリフレクション、動的、またはその他のランタイムベースの検索を使用しないわけではありません。古典的なポリモーフィズムベースのアプローチは、クラスに共通のメソッド (あなたの などMakeNoise()) を持つことです。Animal

于 2013-09-30T20:01:55.747 に答える
0

void MakeNoise() を含む IActions と呼ばれるインターフェイスを作成してから、さまざまな動物の種類でインターフェイスを実装すると、より拡張性が高くなります。

各動物がメソッドを使用する方法をオーバーライドします。次に、メソッドを呼び出すだけです...例

public class Dog : Animal, IActions //Just import the Interface here
{

//Interface for Makenoise

 public void MakeNoise()
 {
    //Its implementation... Make this different for each animal
 }

}

于 2013-09-30T20:08:24.387 に答える