【发布时间】:2012-03-21 14:37:13
【问题描述】:
我似乎经常遇到这种情况,但还没有找到我认为可以接受的解决方案。
我经常会有并行继承层次结构,其中一个层次结构中的方法从另一个层次结构中传递匹配的类作为参数。
这是一个可能更好地解释这一点的示例。
abstract class Animal
{
public virtual void Eat(Food f)
{
}
}
abstract class Food
{
}
class LionFood : Food
{
}
class ElephantFood : Food
{
}
class Lion : Animal
{
public override void Eat(Food f)
{
// It is only ever valid to pass LionFood here as the parameter.
// passing any other type of Food is invalid and should be prevented
// or at least throw an exception if it does happen.
}
}
过去,我通常将基类设为泛型,以允许实现的具体类定义类型如下..
abstract class Animal<T> where T : Food
{
public abstract void Eat(T f);
}
class Lion : Animal<LionFood>
{
public override void Eat(LionFood f)
{
}
}
起初这似乎是一个很好的解决方案,因为它提供了编译时类型安全。但是我用得越多,我就越开始认为以这种方式使用泛型实际上是anti-pattern。问题是 Animal 基类不能以多态方式使用。例如,你不能轻易地编写一个方法来处理任何类型的 Animal,而不管它的实际具体类型如何。
每次我使用这个泛型解决方案时,我似乎总是在各处使用协变和逆变接口,只是为了尝试提供我想要的多态行为。这很快就会失控,并且仅仅因为无法提供正确的界面而无法实现某些功能。
当然,另一种选择是不使用泛型并在 Eat 方法中执行运行时类型检查,如下所示:
public override void Eat(Food f)
{
if (f.GetType() != typeof(LionFood))
{
throw new Exception();
}
}
我想这总比没有好,但我不是它的忠实粉丝,仅仅是因为缺乏编译时类型安全性。
毕竟……我的问题是……提供多态行为同时确保某种类型安全的最佳实践是什么?
是否有一些我缺少的 OO 设计技巧或模式可以让我一起避免并行继承层次结构?
我很欣赏这个问题有些主观,但每个贡献的人都有积分,我会选择最佳答案作为答案。
感谢收看。
编辑:
考虑到这一点,我意识到我给出的示例并没有真正的意义。当然,不可能以多态方式使用 Animal,因为传递给 Eat 的类型将始终取决于 Animal 的实际底层类型(多态调用的发起者不会知道)!我需要想一个更好的例子来说明我的实际情况。
【问题讨论】:
-
您能否举一个您认为设计存在问题的代码示例?
-
为什么不只创建泛型方法而不是泛型类?
-
@VictorSorokin 我已经尽可能地概括了这个,所以我不确定我可以提供哪些进一步的代码示例。我设计的问题是泛型解决方案不允许多态行为(不会变得非常混乱),并且类型检查不提供任何编译时安全性。
-
我不明白你到底想要什么。你想让动物吃一些共同的东西,但是,你又不希望它们能吃任何共同的东西?
-
@enobayram 是的,我认为你在暗示我做错了什么。我只需要弄清楚什么是正确的方法。狮子只会吃LionFood,大象只会吃ElephantFood。但在 Food 中,有一些常见的 Eat 功能是所有 Animals 共有的。
标签: oop design-patterns polymorphism software-design