use*_*188 5 java inheritance abstract-class abstract
给定一个抽象类
public abstract class AbstractStomach {
public abstract void consume(Food food);
}
Run Code Online (Sandbox Code Playgroud)
我想要一些具有不同重载方法的具体类:
public class FruitStomach extends AbstractStomach {
public static class Apple extends Food {}
public static class Orange extends Food {}
@Override
public void consume(Apple food) {...}
@Override
public void consume(Orange food) {...}
}
public class MeatStomach extends AbstractStomach {
public static class Beef extends Food {}
@Override
public void consume(Beef food) {...}
}
Run Code Online (Sandbox Code Playgroud)
以上不起作用,因为它迫使我consume(Food)在每个具体类中也实现通用抽象方法。
但是我不希望具体类实现,consume(Food)因为它们已经被它们的重载变体处理了,实际上,每个具体类应该只消耗不同的特定食物,而不是任何食物,所以
AbstractStomach stomach = new FruitStomach();
stomach.consume(new Beef());
Run Code Online (Sandbox Code Playgroud)
应该给出一个错误。
如果我删除抽象类中的抽象方法,那么让他们扩展抽象类就没有意义了,因为它没有指导他们实现什么。
您如何修复上述设计,以便每个具体类都可以有它们的重载方法,但它们知道有一个抽象方法consume()要实现但不需要实现consume(Food)。
编辑
我可以在不使用重载的情况下解决上述问题,例如
public class FruitStomach extends AbstractStomach {
public static class Apple extends Food {}
public static class Orange extends Food {}
@Override
public void consume(Food food) {
if (food instanceof Apple) {
...
} else if (food instanceof Orange) {
...
} else {
// throws an error
}
}
}
Run Code Online (Sandbox Code Playgroud)
但这不是我想要的。我想看到一个使用方法重载的解决方案。
抽象类中的抽象方法不仅仅是“提供实现内容的指导”。抽象类允许您拥有可以属于抽象类的任何子类的对象。也就是说,你可以有这样的方法
public void evaluateDigestion(AbstractStomach stomach) {
}
Run Code Online (Sandbox Code Playgroud)
你可以用任何类型的Stomach对象来调用它,aFruitStomach或MeatStomachaDessertStomach或a等等。里面的evaluateDigestion方法可以调用stomach.consume(someKindOfFood)。由于这是consume为抽象类定义的(在编译时,evaluateDigestion不知道该类是什么),因此它consume使用了Food参数。然后,在运行时,对的调用consume将“分派”到consume(Food food)为具体类定义的方法。这就是为什么必须为每个具体类定义带有参数的consume原因。Food调度调用不会通过重载方法进行搜索Apple,Orange;Java 不这样做。(所以你的说法“它已经被重载变体处理了”是不正确的;重载和重写之间有很大的区别,这可能会让新手感到困惑。)
所以你必须写
public void consume(Food food)
Run Code Online (Sandbox Code Playgroud)
在每个具体的类中。实现这一点的一种非常笨拙的方法是
public void consume(Food food) {
if (food instanceof Apple) {
consume((Apple)food); // calls the overloaded version because you've use a cast to tell Java how to view the object
} else if (food instanceof Orange) {
consume((Orange)food);
} else {
throw ... // some exception that occurs when you try to eat the wrong kind of food
}
}
Run Code Online (Sandbox Code Playgroud)
更好的方法是在 中定义一个抽象方法Food,假设Food是抽象的:
public abstract class Food {
public void abstract consumedBy(AbstractStomach stomach);
}
Run Code Online (Sandbox Code Playgroud)
Apple在和等类中定义具体版本Orange,然后编写consume如下
public static void consume(Food food) {
food.consumedBy(this);
}
Run Code Online (Sandbox Code Playgroud)
然而,这并不能阻止人们尝试FruitStomach吃牛肉。您可能需要使用它instanceof来确保食物兼容。(一种可能性:定义一个Fruit扩展 的类Food,并创建 的Apple子Orange类Fruit;然后你可以说food instanceof Fruit验证它是正确的食物种类。不过,可能有比这更好的设计模式。我想不出一个即兴的设计模式.)