Как использовать полиморфизм подтипов и дженерики для списков? - PullRequest
1 голос
/ 27 марта 2019

Я изучаю Java и прочитал о наследовании и полиморфизме подтипов.Сейчас я только начинаю изучать дженерики и пытаюсь собрать их воедино, но я застрял.

Скажем, у меня есть abstract родительский класс AbstractEdibles, и есть двадети, которые extend от него: Food и Drink.Кроме того, у меня есть Store, который имеет два List s: один для хранения Food и один для хранения Drink.

Теперь я хочу, чтобы мой Store мог иметьповедения, такие как добавление к его запасу. Мой желаемый подход - это определить один метод, чтобы взять продукт и поместить его в соответствующий список.Если это тип Food, поместите его в список продуктов.Если это тип Drink, включите его в список напитков.

Я уверен, что мне нужно использовать дженерики и полиморфизм подтипов.Вот фрагмент моего кода:

public class Store {

  private List<AbstractEdible> foodStock = new ArrayList<>();
  private List<AbstractEdible> drinkStock = new ArrayList<>();

  /**
   * A constructor for a new store inventory that has food and drink.
   *
   * @param foodStock   the list of food items in stock
   * @param drinkStock  the list of drink items in stock
   */
  public Store(List<AbstractEdible> foodStock, List<AbstractEdible> drinkStock) {
    this.foodStock = foodStock;
    this.drinkStock = drinkStock;
  }

  /**
   * Given an edible food, add it to its respective stock list.
   *
   * @param edible an edible item
   */
  public void addItemToStock(AbstractEdible edible) {
    if (product instanceof Food) {
      this.foodStock.add(product);
    } else if (product instanceof Drink) {
      this.drinkStock.add(product);
    }
  }
}

Это не дает ошибок, но я недоволен тем, насколько свободным я являюсь с типами, и я думаю, что это можно сделать более оптимальным.

Для начала, я бы предпочел, чтобы в моем списке только разрешался этот конкретный тип edible.То есть foodStock разрешит добавление только Food, а drinkStock разрешит добавление только Drink.Я попробовал:

private List<AbstractEdible> foodStock = new ArrayList<Food>();
private List<AbstractEdiblet> drinkStock = new ArrayList<Drink>();

дает мне красное подчеркивание в моей IDE.Затем я изменил на:

private List<Food> foodStock = new ArrayList<Food>();
private List<Drink> drinkStock = new ArrayList<Drink>();

это работает, но затем мой метод addItemToStock() жалуется, что edible, который я пытаюсь добавить, имеет тип Edible и не может быть добавлен вList содержащий тип Food.(Это ожидается, потому что Edible является родителем Food; т.е. не каждый Edible является Food, но каждый Food равен Edible.)

Вверх / Вниз приведениеedible тоже не помогает.Затем я подумал, что Upper Bounded Wildcards - это то, что я искал, но это также не сработало.

Кроме того, я также не уверен, что использование instanceof является лучшим способом классификации / сортировки объектов.

Что мне здесь не хватает?Какую концепцию я не понимаю?

1 Ответ

2 голосов
/ 27 марта 2019

Если вы хотите убедиться, что foodStock хранит только Food и drinkStock хранит только Drink, то вам придется инициализировать свои списки следующим образом:

private List<Food> foodStock = new ArrayList<>();
private List<Drink> drinkStock = new ArrayList<>();

Если ониисходят из конструктора, просто объявите их:

private List<Food> foodStock;
private List<Drink> drinkStock;

, а затем присвойте их в конструкторе:

public Store(List<Food> foodStock, List<Drink> drinkStock) {
    this.foodStock = foodStock;
    this.drinkStock = drinkStock;
}

И как только вы используете instanceOf, можно безопасно использовать приведение:

public void addItemToStock(AbstractEdible product) {
    if (product instanceof Food) {
        this.foodStock.add((Food) product);
    } else if (product instanceof Drink) {
        this.drinkStock.add((Drink) product);
    }
}

Вы также можете создать общий Stock класс:

public class Stock<T extends AbstractEdible> {

    private List<T> items;

    public Stock() {
        items = new ArrayList<>();
    }

    public void addItem(T item) {
        this.items.add(item);
    }

    public List<T> getItems() {
        return items;
    }
}

и использовать его в своем Store как:

public class Store {
    private Stock<Food> foodStock;
    private Stock<Drink> drinkStock;

    public Store() {
        this.foodStock = new Stock<>();
        this.drinkStock = new Stock<>();
    }

    public Store(Stock<Food> foodStock, Stock<Drink> drinkStock) {
        this.foodStock = foodStock;
        this.drinkStock = drinkStock;
    }

    public void addItemToStock(AbstractEdible product) {
        if (product instanceof Food) {
            this.foodStock.addItem((Food) product);
        } else if (product instanceof Drink) {
            this.drinkStock.addItem((Drink) product);
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...