C# 继承/多态

本文关键字:多态 继承 | 更新日期: 2023-09-27 18:33:19

假设以下类:

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 基类?

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

C# 继承/多态

我可以想到几种可以实现上述方法的方法。

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"
    
  • 允许类似于调解员的东西根据动物的类型转发请求,等等:

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

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

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

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

您可以通过界面进行操作,该接口与您的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()并让基类(或接口(定义它。

如果你创建了一个名为IActions的接口,其中包含一个空的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
 }

}