并行继承链中的多态性和类型安全
我有两个并行的继承链:
Chain1:
Animal <- Lion
<- Gazelle
Chain2:
Food <- Meat
<- Grass
我想在 Animal 上实现“Eats”多态属性。 它是这样的:
public abstract class Animal
{
public abstract Food Eats { get; set;}
}
public class Lion : Animal
{
public override Food Eats
{
get { return new Meat();}
set
{
if (value is Meat) DoSomething(value);
else throw new Exception("Lions only eat meat. " +
"You better learn that, dude!");
}
}
}
但是,此代码不是类型安全的。 如果我用草喂我的狮子,我只会在运行时遇到我的虫子。
有人可以为我提供一个代码示例,该示例可以在不牺牲多态性的情况下使用泛型促进类型安全吗?
I have two parallel inheritance chains:
Chain1:
Animal <- Lion
<- Gazelle
Chain2:
Food <- Meat
<- Grass
I want to implement the "Eats" polymorphic property on Animal. This is how it looks like:
public abstract class Animal
{
public abstract Food Eats { get; set;}
}
public class Lion : Animal
{
public override Food Eats
{
get { return new Meat();}
set
{
if (value is Meat) DoSomething(value);
else throw new Exception("Lions only eat meat. " +
"You better learn that, dude!");
}
}
}
However, this code is not type safe. Should I feed my Lion with grass, I will be confronted with my bug only in runtime.
Could someone provide me with a code example that facilitates type safety using Generics without sacrificing polymorphism?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用组合而不是继承:
不要根据消化系统进行继承,而是将消化分解为自己的一组类。
首先,一个描述不同饮食方式的界面。
肉食动物吃肉,有时可以吃草药,不喜欢垃圾:
草食动物很挑剔,宁愿死也不吃肉(我知道,保存你的评论,这是一个例子)
杂食动物什么都吃。 见证州博览会。
所有动物都必须进食,因此它们必须有消化系统以及其他系统。
嬉皮士是一个品味众所周知的动物阶层。 它在实例化时配置自身。 也可以从外部注入行为和系统。
最后,让我们看看嬉皮士吃汉堡。
当对动物等复杂系统进行建模时,我更喜欢组合而不是继承。 复杂的系统可以快速地爆炸继承树。 以三种动物系统为例:杂食动物/草食动物/肉食动物,水/空气/陆地,以及夜间/白天。 我们甚至不用担心如何决定哪个分类成为动物的第一个区分点。 我们是否首先将动物延伸到食肉动物,首先延伸到水生动物,还是首先延伸到夜行动物?
由于杂食动物可以生活在空中并喜欢夜晚(蝙蝠*),也可以是白天行走的陆地生物(人类),所以你必须有一条能够满足每一个选项的继承路径。 这是一个已经有 54 种不同类型的继承树(还为时过早,请友善)。 动物比这复杂得多。 您可以轻松获得具有数百万种类型的继承树。 绝对是组合优于继承。
*例如,新西兰短尾蝙蝠是杂食性的。
Using composition over inheritance:
Instead of inheriting based on digestive system, break off digestion into its own set of classes.
First, an interface that describes different ways to eat.
Carnivores eat meat, can eat herbs sometimes, and don't like crap:
Herbivores are picky and would rather die than eat meat (I know, save your comments, this is an example)
Omnivores eat anything. Witness a state fair.
All animals must eat, so they must have a digestive system, along with other systems.
Hippies are an animal class with known tastes; it configures itself on instantiation. It is also possible to inject behaviors and systems from the outside.
And finally, let's see a hippie eat a burger.
When modeling complex systems like animals, I'd prefer composition over inheritance ANY DAY. Complex systems can explode an inheritance tree with the quickness. Take three animal systems: omnivore/herbivore/carnivore, water/air/land, and nocturnal/diurnal. Let's not even worry about how to decide which classification becomes the first point of differentiation for Animals. Do we extend Animal to Carnivore first, to WaterLiving first, or to Nocturnal first?
Since an omnivore can live in the air and prefer the night (bat*) and also be a day walking land creature (humans), you have to have an inheritance path that hits every single option. That's an inheritance tree with 54 different types already (its early, be kind). And Animals are much more complex than this. You could easily get an inheritance tree that had millions of types. Composition over inheritance, definitely.
*New Zealand Short Tailed bat, for example, is omnivorous.
动物可以是一个通用类:
然后你可以让狮子成为这样的食肉动物
但这不是一个最佳解决方案。 您不能再将animal用作多态接口,因为您需要了解其实现的详细信息才能使用它。 这可能不适合多态性。
Animal can be a generic class:
then you can make lion a meat eating animal like this
But this is not be an optimal solution. You can't use animal as a polymorphic interface any more because you need to know details about it's implementation to use it. This might just not be the place for polymorphism.
嗯,也许你可以修改你的第一个继承链:
动物
- 食肉动物
- 狮子
- 老虎
- ...
- 草食动物
- 羊
那么,你也许可以做这样的事情:
我还没有测试过,这只是我的一个想法......
Hmm, maybe you could modify your first inheritance chain:
Animal
- Carnivore
- Lion
- Tiger
- ...
- Herbivore
- Sheep
Then, you could maybe do something like this:
I haven't tested, it is just an idea that I have ...
我认为这有点虚假的困境。 食物似乎比抽象基类更接近接口,因为听起来肉与草根本不相似。 相反,请考虑以下内容:
I think this is a bit of a false dilemma. Food seems to be closer to an interface than an abstract base class, since it doesn't sound like Meat is going to be very similar to Grass at all. Instead, consider something like: