2

Assume the follwing classes:

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

Is this possible? Without adding a method like MakeNoise() to the Animal base class?

In my Application I have a CatFactory and a DogFactory, which implement AnimalFactory and return Animals. I cant call Meow/bark in the factory and I cant call it after I got the animals.

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

我可以想出几种方法来实现类似上面的东西。

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();
    }
}

除了这两个明显的实现之外,您可能还需要考虑这些:

  • 使用装饰器动态增强类的功能。(类似于上面的“包装器”方法,但更清晰地融入到类结构中。)

  • 实现您的类可以动态处理的一系列Command对象:

    cat.Do( new MakeNoiseCommand() ); // Handled as "meow"
    dog.Do( new MakeNoiseCommand() ); // Handled as "bark"
    
  • 允许类似于Mediator的东西根据 Animal 的类型等转发请求:

    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

这可能吗?没有向 Animal 基类添加像 MakeNoise() 这样的方法?

并非不使用反射、动态或其他一些基于运行时的搜索来调用方法。经典的基于多态性的方法是在类中有一个通用方法(如 your MakeNoise()Animal

于 2013-09-30T20:01:55.747 回答
2

在您的示例代码中,没有Animal多态的行为 - 也就是说,对基类的引用的相同消息会导致执行不同的具体行为。

于 2013-09-30T20:02:41.110 回答
0

如果您创建了一个名为 IActions 的接口,其中包含一个 void MakeNoise() 然后在不同的动物类型上实现该接口,那么它会更具可扩展性。

覆盖每只动物使用方法的方式。然后只需调用该方法...示例

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 回答