我正在实现一个类的集合,它们表现出以下模式:
public class Animal {}
public abstract class AnimalToy
{
public AnimalToy(Animal owner)
{
Owner = owner;
}
public Animal Owner { get; private set; }
/* Various methods related to all toys that use the Owner property */
}
public class Dog: Animal
{
public void Bark() {}
}
public class PlasticBone: AnimalToy
{
public PlasticBone(Dog owner) : base(owner) {}
public void Throw()
{
((Dog)Owner).Bark();
}
}
- 我有一个基类
AnimalToy
,其属性是对另一个基类Animal
的引用。 - 我现在想为
Dog
类实现Dog
和PlasticBone
玩具。PlasticBone
是一个只对狗有效的玩具,实际上构造器限制PlasticBone
的主人为Dog
类型。 -
PlasticBone
有一个惟一的Throw()
方法,它使用Dog
(Bark()
)上惟一的Dog
类的方法。因此,在我可以访问它之前,我需要将通用属性Owner
转换为Dog
。
这工作得很好,但在项目中,我正在处理这种情况一次又一次地出现,并导致相当丑陋的代码,其中派生类的方法充满了基类引用的向下转换。这正常吗?或者有没有更好的整体设计更干净?
有一种方法可以解决这个问题:
public abstract class Animal
{
public abstract void MakeNoise();
}
让dog实现MakeNoise,你可以在你的Toy类中调用它:
public void Throw()
{
Owner.MakeNoise();
}
可以将AnimalToy
类设置为泛型,这样可以避免强制类型转换。
public abstract class AnimalToy<TAnimal> where TAnimal : Animal
{
public AnimalToy(TAnimal owner)
{
Owner = owner;
}
public TAnimal Owner { get; private set; }
}
public class PlasticBone: AnimalToy<Dog>
{
public PlasticBone(Dog owner) : base(owner) {}
public void Throw()
{
Owner.Bark();
}
}
值得注意的是,((Dog)Owner)
不是上cast,它被称为下cast。
我将尝试在评论中详细说明一些讨论,并希望为您提供一个通用的多态解决方案。总体思想在功能上与Carra所建议的相同,但希望这将帮助您将这些概念应用于实际问题的领域。
对你的问题进行抽象处理;假设您的抽象基类定义如下:
public abstract class Animal
{
public abstract void Catch();
}
这是抽象方法语义上的一个转变;您不再拥有抽象的Bark
方法,您只拥有一个Catch
方法,其语义将其定义为"对抛出的内容做出反应"。Animal
的反应完全取决于动物。
那么,你可以这样定义Dog
:
public class Dog : Animal
{
public override void Catch()
{
Bark();
}
public void Bark()
{
// Bark!
}
}
并将Throw
方法更改为:
public void Throw()
{
Owner.Catch();
}
现在,Bark
是特定于Dog
的,而通用的Catch
方法是通用于所有Animal
的。Animal
类现在指定它的子类必须实现一个方法,该方法对抛出给它的项作出反应。事实上,Dog
的吠叫完全取决于Dog
。
这就是多态性的本质——不能由玩具来决定狗做什么;这取决于狗。玩具只需要知道狗能抓住它。
更一般地说,我不喜欢两个扩展独立基类的类在逻辑上耦合(并行层次结构,正如Eric指出的那样),除非其中一个显式实例化另一个,尽管在没有看到实际的解决方案架构之前,不可能提供任何真正的建议。