2014-11-04 69 views
2

在我的程序中,我有抽象类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执行此更好的方法?

回答

2

是的,还有更好的办法。您可能不希望在参数中强制执行该类型。

原因是,运行时和编译时多态性之间存在主要差异。现在,当你编译代码时,你必须知道(全部)动物可以吃的花的类型。这样可以防止在没有代码更新的情况下更改该数据,并且会失去相当数量的抽象。

Animal的合同是它吃了某种类型的Flower,但你不知道马上就知道那是什么。事实上,只有那个特定的动物确切地知道它喜欢什么类型的花。也许你有一个Rhino与不容忍BlueRose s,谁只吃RedRose s。

除非您毫无疑问地知道所有Rhino s都会吃掉所有的Rose s并且愿意永远保持这种情况(或者直到您的下一个主要版本),否则您不应该将其作为界面的一部分公共合同。在不久的将来某个时候,Rhino可能会意识到Daisies同样美味,并且一个亚种可以同时吃掉。一旦公开,你只能使它更少限制。

Rhino出现Flower时,它必须选择是否配备吃特定的花。犀牛每天早上醒来时都没有列出所有好花,所以你可能不应该在代码中硬编码。

根据您希望如何执行该选择,您有两种选择。你可以检查通过的Flower是一个instanceof一个已知好的类型,它需要你知道所有好的类型是编译时。您也可以将FlowerType getType()方法添加到Flower s,调用该方法,并将结果与​​Set<FlowerType> goodFlowers`进行比较。这允许你在运行时改变可接受的花朵,如果这样的事情是必要的。

一般来说,多个instanceof检查(如果犀牛可以吃另一种花,你会得到)通常可以作为设计缺陷的指标。它们可以通过紧密绑定两个不相关的类型来损害抽象,并且可以用数据(来自枚举,数据库,文件或其他源)替换。

2

您可以使用泛型。类似这样的:

public abstract class Animal<T extends Flower> { 
    abstract void eatFlower(T f); 
} 

public class Rhino extends Animal<Rose> { 
    void eatFlower(Rose f) { 

    } 
} 
相关问题