子类作为抽象方法的参数

时间:2014-11-04 19:04:58

标签: java oop polymorphism instanceof

在我的程序中,我有抽象类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 个答案:

答案 0 :(得分:2)

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

原因是,运行时和编译时多态之间存在重大差异。现在,你必须知道(所有)动物在编译代码时可以吃的花的种类。这可以防止您在没有代码更新的情况下更改该数据,并且会丢失相当多的抽象。

Animal的合同是它吃某种类型的Flower,但你不知道它是什么。事实上,只有那个特定的动物才知道它喜欢什么类型的花。也许你有一个RhinoBlueRose不容忍,只能吃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) {

    }
}