簡體   English   中英

在JAVA中使用一個抽象方法的重載方法

[英]Having overload methods from one abstract method in JAVA

給出一個抽象類

public abstract class AbstractStomach {
    public abstract void consume(Food food);
}

我想要一些具有不同重載方法的具體類:

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) {...}
}

上面的方法不起作用,因為它迫使我在每個具體類中實現泛型consume(Food)抽象方法。

但是我不希望具體的類實現consume(Food)因為它們已經由它們的重載變體來處理,實際上,每個具體的類應該只消耗不同的特定食物,而不是任何食物,所以

AbstractStomach stomach = new FruitStomach();
stomach.consume(new Beef());

應該給出錯誤。

如果我在抽象類中刪除抽象方法,那么就沒有必要讓它們擴展抽象類,因為它沒有為它們提供實現的指導。

你如何修復上面的設計,以便每個具體的類可以有他們的重載方法,但他們知道有一個抽象方法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
        }
    }
}

但這不是我想要的。 我想看到一個使用方法重載的解決方案。

抽象類中的抽象方法不僅僅是“提供實現指導”。 抽象類允許您擁有可以是抽象類的任何子類的對象。 也就是說,你可以有類似的方法

public void evaluateDigestion(AbstractStomach stomach) {
}

你可以用任何一種Stomach對象, FruitStomachMeatStomach或者DessertStomach或其他任何東西來調用它。 evaluateDigestion里面,該方法可以調用stomach.consume(someKindOfFood) 由於這是為抽象類定義的consume (在編譯時, evaluateDigestion不知道類是什么),因此它是使用Food參數的consume 然后,在運行時,對consume的調用將“調度”到為具體類定義的consume(Food food)方法。 這就是必須為每個具體類定義帶有Food參數的consume的原因。 調度調用不會搜索帶有AppleOrange等參數的重載方法; Java不會這樣做。 (所以你的聲明“它已經由重載變量處理”是不正確的;重載和覆蓋之間存在很大的區別,這可能會讓新手感到困惑。)

所以你必須寫

public void consume(Food food)

在每個具體的課堂上。 一個非常笨重的方法來實現這一點

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

更好的是在Food定義一個抽象方法,假設Food是抽象的:

public abstract class Food {
    public void abstract consumedBy(AbstractStomach stomach);
}

AppleOrange等類中定義具體版本,然后編寫類似的consume

public static void consume(Food food) {
    food.consumedBy(this);
}

然而,這並不妨礙嘗試讓FruitStomach消費牛肉。 您可能必須使用instanceof來確保食物兼容。 (一種可能性:定義一類延伸Food Fruit ,制作Fruit AppleOrange類;然后你可以說food instanceof Fruit來驗證它是正確的食物類型。但是可能有比這更好的設計模式。我不能想到一個隨便。)

您可以使用泛型來(部分)解決您的問題:

AbstractStomach定義了一個類型參數T ,它聲明了它消耗的Food類型:

public abstract class AbstractStomach<T extends Food> {
    public abstract void consume(T food);
}

然后你可以聲明一個食物類型Fruit和相應的FruitStomach

public class Fruit extends Food {}
public class FruitStomach extends AbstractStomach<Fruit> {
    public static class Apple extends Fruit {}
    public static class Orange extends Fruit {}
    @Override
    public void consume(Fruit food) {}
}

和類似的類MeatMeatStomach

public class Meat extends Food {}
public class MeatStomach extends AbstractStomach<Meat> {
    public static class Beef extends Meat {}
    @Override
    public void consume(Meat food) {}
}

要@Override方法,您需要具有相同的返回條件或子類型,名稱和參數,以便您無法更改“橙色橙色”中的“食物食物”。

我認為你可以做的是對你需要在具體類中的方法內部工作的對象進行強制轉換(或者使用instanceof)。 或者更好的是你可以創建一個對象:

Food orange = new Orange();
Food apple = new Apple(); 

因此,在Orange類中使用第一次方法覆蓋,第二次使用Apple類中的一個方法。

如果它不是您想要的解決方案,請發表評論,以便我可以嘗試別的東西。

The above doesn't work as it is forcing me to implement also the generic consume(Food)

這是正確的行為。 通過抽象類AbstractStomach合同,您同意,

擴展AbstractStomach任何東西都會有一個方法consume(Food)任何食物 )然后在子類中你強迫它只有兩種類型的食物,從而繞過合同。

您遇到的問題是您的抽象方法簽名需要將名為Food的超類傳遞給consume-method。 此抽象類的每個實現(以及它的抽象方法)都必須覆蓋相同的簽名。

例如

   public FruitStomach extends AbstractStomach {
    public static class Apple extends Food {}
    public static class Orange extends Food {}
    @Override
    public void consume(Food food) {
      if (food instanceof Orange) {
        Orange orange = (Orange) food;
        // do smth. with orange     
      } else{
        // so smth with food
      }
    }

   public MeatStomach extends AbstractStomach {
      public static class Beef extends Food {}
      @Override
      public void consume(Food food) {
        Beef beef = (Beef) food;
        // do smth. with beef...
      }
    }

可以工作。 雖然這不是非常干凈的代碼,但如果您的代碼正確連接在一起,則無法進行編譯時驗證。 但正如你所說,如果你在錯誤的輸入食物上調用錯誤的Stomach.consume() - 方法,你可能會引發一個ClassCastException,你可以處理它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM