【问题标题】:c# inheritance / polymorphyc#继承/多态
【发布时间】:2013-09-30 20:00:03
【问题描述】:

假设以下类:

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

这可能吗?不向 Animal 基类添加 MakeNoise() 之类的方法?

在我的应用程序中,我有一个 CatFactory 和一个 DogFactory,它们实现了 AnimalFactory 并返回 Animals。我不能在工厂里叫喵/吠,我拿到动物后也不能叫它。

【问题讨论】:

  • 正如@Reed 建议的那样,你不能这样做没有反射。但是,如果您确实反映了,您可以简单地为您的 BarkMeow 方法添加一个属性,可能称为 [MakeNoise],这将允许不同的方法名称。

标签: c# inheritance polymorphism


【解决方案1】:

我可以想出几种方法来实现上述内容。

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。使用Adapters

如果您无法访问原始源代码,适配器可能是唯一的选择。您可以使用它们来“同步”您的代码访问 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();
    }
}

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

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

  • 实现您的类可以动态处理的一系列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();
        }
    }
    

【讨论】:

    【解决方案2】:

    这可能吗?不向 Animal 基类添加 MakeNoise() 之类的方法?

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

    【讨论】:

    • 为什么是多态性或动态性?只需打开 Type()。
    • @JeroenvanLangen 是的 - 但如果该方法不存在,它将在运行时抛出。 (我也不会让它变得邪恶;))
    • 如果你可以简单地实现接口,你为什么要这样做(反射/动态)?
    • @Ela 你不会,通常 - 你会做一个常见的方法,所以你可以使用接口。这个问题专门说他不想将它添加到界面中;)
    • @ReedCopsey 好吧,我假设他只是不知道 ;)
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      你可以通过一个界面来做,这和你的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() 和让基类(或接口)定义它。

      【讨论】:

        【解决方案5】:

        如果您创建一个名为 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
         }
        

        }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-09-11
          • 2015-07-30
          • 2013-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多