JAVA 中一种抽象方法的重载方法

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)

但这不是我想要的。我想看到一个使用方法重载的解决方案。

ajb*_*ajb 5

抽象类中的抽象方法不仅仅是“提供实现内容的指导”。抽象类允许您拥有可以属于抽象类的任何子类的对象。也就是说,你可以有这样的方法

public void evaluateDigestion(AbstractStomach stomach) {
}
Run Code Online (Sandbox Code Playgroud)

你可以用任何类型的Stomach对象来调用它,aFruitStomachMeatStomachaDessertStomach或a等等。里面的evaluateDigestion方法可以调用stomach.consume(someKindOfFood)。由于这是consume为抽象类定义的(在编译时,evaluateDigestion不知道该类是什么),因此它consume使用了Food参数。然后,在运行时,对的调用consume将“分派”到consume(Food food)为具体类定义的方法。这就是为什么必须为每个具体类定义带有参数的consume原因。Food调度调用不会通过重载方法进行搜索AppleOrange;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,并创建 的AppleOrangeFruit;然后你可以说food instanceof Fruit验证它是正确的食物种类。不过,可能有比这更好的设计模式。我想不出一个即兴的设计模式.)