在我的程序中,我有抽象类Animal和Flower。动物吃花,但每只动物只应该吃某种花(例如犀牛只吃玫瑰,海龟吃郁金香)。
现在我的代码基本上是这样的:
public abstract class Animal {
abstract boolean eatFlower(Flower f);
}
public class Rhino extends Animal {
boolean eatFlower(Flower f) {
if(!(f instanceof Rose)) return false;
return (f.eaten = true);
}
}
public class Turtle extends Animal {
boolean eatFlower(Flower f) {
if(!(f instanceof Tulip)) return false;
return (f.eaten = true);
}
}
我使用instanceof
强制执行此区分,其中每个动物只吃一种类型的花。我想通过将Turtle和Rhino的方法签名分别更改为eatFlower(Tulip t)
和eatFlower(Rose r)
来实现,但我不认为这在Java中是可行的。
有没有比使用instanceof
更好的方法来执行此操作?
答案 0 :(得分:2)
是的,还有更好的方法。您可能不希望在参数中强制执行该类型。
原因是,运行时和编译时多态之间存在重大差异。现在,你必须知道(所有)动物在编译代码时可以吃的花的种类。这可以防止您在没有代码更新的情况下更改该数据,并且会丢失相当多的抽象。
Animal
的合同是它吃某种类型的Flower
,但你不知道它是什么。事实上,只有那个特定的动物才知道它喜欢什么类型的花。也许你有一个Rhino
对BlueRose
不容忍,只能吃RedRose
s。
除非你毫无疑问地知道所有Rhino
将会吃掉所有Rose
并愿意承诺永远(或直到你的下一个主要版本),你不应该使其成为界面公共合同的一部分。在不久的将来的某个时刻,Rhino
可能会意识到Daisies
同样美味,并且出生的亚种可以同时吃两种。一旦某些内容公开,您只能减少限制。
当Rhino
来到Flower
时,它必须选择是否配备吃特定的花。犀牛每天早上醒来时都没有列出所有好花,所以你可能不应该在你的代码中对它们进行硬编码。
您有两种选择,具体取决于您希望如何强制执行该选择。您可以检查传递的Flower
是否为instanceof
已知良好类型,这要求您知道所有良好类型都是编译时。您还可以向FlowerType getType()
添加Flower
方法,调用该方法,并将结果与Set<FlowerType>
goodFlowers`进行比较。如果需要,可以在运行时更改可接受的花朵。
一般来说,多次instanceof
检查(如果犀牛可以吃另一种花,你会得到的)通常可以作为设计缺陷的指标。它们可以通过紧密绑定两个不相关的类型来破坏抽象,并且可以用数据(来自枚举,数据库,文件或其他来源)替换。
答案 1 :(得分:2)
您可以使用泛型。像这样:
public abstract class Animal<T extends Flower> {
abstract void eatFlower(T f);
}
public class Rhino extends Animal<Rose> {
void eatFlower(Rose f) {
}
}