简体   繁体   English

子类作为抽象方法的参数

[英]Subclasses as arguments to abstract method

In my program I have abstract classes Animal and Flower. 在我的程序中,我有动物和花卉抽象类。 Animals eat Flowers, but each Animal is only supposed to eat a certain type of flower (eg Rhinos only eat Roses, Turtles eat Tulips). 动物会吃花,但每个动物只能吃某种类型的花(例如,犀牛只吃玫瑰,乌龟只吃郁金香)。

Right now my code basically looks like this: 现在,我的代码基本上看起来像这样:

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);
    }
}

I'm using instanceof to enforce this distinction where each Animal eats only one type of Flower. 我使用instanceof来实现这种区分,即每个动物只吃一种花。 I'd like to do it by changing the method signatures of Turtle and Rhino to eatFlower(Tulip t) and eatFlower(Rose r) , respectively, but I don't think this is possible in Java. 我想通过将Turtle和Rhino的方法签名分别更改为eatFlower(Tulip t)eatFlower(Rose r) ,但是我认为这在Java中是不可能的。

Is there a better way than using instanceof to enforce this? 有没有比使用instanceof强制执行此方法更好的方法?

Yes, there is a better way. 是的,有更好的方法。 You probably don't want to enforce that type in the parameter. 您可能不想在参数中强制使用该类型。

Reason being, there is a major difference between run-time and compile-time polymorphism. 原因是,运行时和编译时多态性之间存在很大的差异。 Right now, you have to know (all) the types of flower an animal can eat when you compile the code. 现在,您必须知道(全部)动物在编译代码时可以吃的花的类型。 This prevents you from changing that data without a code update, and loses a fair amount of abstraction. 这样可以防止您在不进行代码更新的情况下更改该数据,并且会损失大量抽象。

The contract of an Animal is that it eats some type of Flower , but you don't know what that is right away. Animal的契约是它吃某种类型的Flower ,但您不知道那是什么。 In fact, only that particular animal knows exactly what type of flower it likes. 实际上,只有那种动物才能确切知道它喜欢哪种花。 Perhaps you have a Rhino with an intolerance to BlueRose s, who has to eat only RedRose s. 也许你有一个Rhino与不容忍BlueRose S,谁拥有只吃RedRose秒。

Unless you know without any doubt that all Rhino s will eat all Rose s and are willing to commit to that being the case forever (or until your next major version), you shouldn't make it a part of the interface's public contract. 除非您毫无疑问地知道所有Rhino都将吃掉所有Rose并愿意永远这样(或者直到您的下一个主要版本为止),否则您不应该将其作为接口公共合同的一部分。 At some point in the near future, Rhino s may realize that Daisies are equally delicious, and a sub-species is born that can eat both. 在不久的将来的某个时候, Rhino可能意识到Daisies同样美味,并且诞生了可以同时食用两者的亚种。 Once something is public, you can only make it less restrictive. 一旦公开,您就只能减少限制。

When a Rhino comes upon a Flower , it has to choose whether or not it is equipped to eat that particular flower. Rhino Flower ,它必须选择是否有能力吃掉那朵特定的花。 The rhino does not list all good flowers when it wakes up every morning, so you probably shouldn't hard-code them all in your code. 犀牛每天早上醒来时都不会列出所有好的花朵,因此您可能不应该在代码中全部将它们硬编码。

You have two options, depending on how you want to enforce that choice. 您有两个选择,具体取决于您要如何执行该选择。 You can check that the passed Flower is an instanceof a known-good type, which requires you to know all good types are compile-time. 您可以检查传递的Flower是否是已知有效类型的instanceof ,这要求您知道所有良好类型都在编译时。 You could also add FlowerType getType() method to Flower s, call that, and compare the results with a Set<FlowerType> goodFlowers`. 您还可以将FlowerType getType()方法添加到Flower ,对其进行调用,然后将结果与Set<FlowerType> goodFlowers`进行比较。 That allows you to change the acceptable flowers at runtime, if such a thing is necessary. 如有必要,您可以在运行时更改可接受的花朵。

Speaking generally, multiple instanceof checks (which you'll get, if rhinos can ever eat another kind of flower) can often be the indicator of a design flaw. 一般来说,多次检查instanceof (如果犀牛可以吃另一种花,您会得到的)通常可以指示设计缺陷。 They can harm abstraction, by closely binding two otherwise-unrelated types, and may be replaced with data (from an enum, database, file, or other source). 通过紧密绑定两个本来无关的类型,它们可能会损害抽象,并可能被数据(来自枚举,数据库,文件或其他来源)替换。

You can use generics. 您可以使用泛型。 Something like this: 像这样:

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

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

    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM