2017-01-15 1 views
2

Мне интересно, как отредактировать мой код, чтобы я мог удалить элементы в методе cleanShelf, основываясь не только на том, прошли ли они их использование по дате, но и по тому, были ли они открыты. Проблема в том, что свойство dateOpened принадлежит только элементам типа DiaryFood, и я не знаю, как получить к нему доступ в моем классе Shelf.Наследование Java: как удалить элементы из ArrayList в зависимости от свойства, которое не принадлежит всем элементам?

Питание:

public abstract class Food { 

    private String name; 
    private int calorieAmount; 
    private int useDate; 

    public Food(String name, int calorieAmount, int useDate) { 
     this.name = name; 
     this.calorieAmount = calorieAmount; 
     this.useDate = useDate; 
    } 

    public String getName() { 
     return name; 
    } 

    public int getuseDate() { 
     return useDate; 
    } 
} 

DiaryFood:

public class DiaryFood extends Food { 

    private int dateOpened; 

    public DiaryFood(String name, int calorieAmount, int useDate, int dateOpened) { 
     super(name, calorieAmount, useDate); 
     this.dateOpened = dateOpened; 
    } 

    public int getdateOpened() { 
     return dateOpened; 
    } 
} 

VegFood:

public class VegFood extends Food { 

    private String colour; 

    public VegFood(String name, int calorieAmount, int useDate, String colour) { 
     super(name, calorieAmount, useDate); 
     this.colour = colour; 
    } 

} 

Полка:

public class Shelf { 

    ArrayList<Food> food; 

    public Shelf() { 
     food = new ArrayList<Food>(); 
    } 


    public void addFood(Food product) { 
     this.food.add(product); 
    } 

    public void printShelfDetails() { 
     for (Food f : food) 
     { 
      System.out.println(f.getName() + " " + f.getuseDate()); 
     } 
    } 

    public void cleanShelf(int day) { 

     ArrayList<Food> foodToRemove = new ArrayList<Food>(); 

     for (int i = 0; i < food.size(); i++) { 
      if (food.get(i).getuseDate() < day) { 
       foodToRemove.add(food.get(i)); 
      } 
     } 

     food.removeAll(foodToRemove); 
    } 
} 

ответ

1

Если вы хотите продолжить работу с объявленными типами Food, и вы хотите избежать манипулирования определенными типами в своей коллекции и или сделать downcasts до DiaryFood, вы можете добавить метод getDateOpened() в класс Food, который возвращает null.

Вы должны изменить возвращаемый тип из int значения для Integer значения для того, чтобы иметь возможность вернуть null значения:

public abstract class Food { 
     public Integer getdateOpened() { 
     return null; 
     } 
} 

В конкретных классах, которые эффективно в dateOpened поле, вы можете изменить его:

@Override 
public Integer getdateOpened() { 
    return dateOpened; 
} 

И, конечно, в других конкретных классах, у которых нет dateOpened поля вы можете сохранить реализацию базы класс: Food.

Таким образом, в цикле можно сделать:

for (int i = 0; i < food.size(); i++) { 
     Foot currentFood = food.get(i); 
     if (currentFood.getuseDate() < day && currentFood.getDateOpened() != null && yourConditionAboutDateOpened) { 
      foodToRemove.add(food.get(i)); 
     } 
    } 
+0

Я бы не предложил этот метод. Это добавляет накладные расходы общественности api в пути. Почему бы не предложить использовать «интерфейс» вместо этого? – Adowrath

+1

интерфейс или нет, если вы не хотите, чтобы бросить, вам нужно изменить api. Все зависит от того, чего хочет пользователь: делать броски или открывать контракт. Вот почему я уточнил это в своем ответе. – davidxxx

+1

Эта часть как-то сбежала из моего сознания, извините. – Adowrath

1
  1. Вы должны проверить, если элемент instance из DiaryFood и сделать соответствующий dateOpened проверить
  2. cleanShelf метод не очень эффективен. Использование iterator или removeIf - лучший и более чистый выбор для удаления элементов из списка.

Пожалуйста, смотрите ниже код

food.removeIf(item -> item.getuseDate() < day 
      || (item instanceof DiaryFood && ((DiaryFood) item).dateOpened < day)); 

или

Iterator<Food> iterator = food.iterator(); 
while (iterator.hasNext()) { 
    Food item = iterator.next(); 
    if (item.getuseDate() < day 
      || (item instanceof DiaryFood 
       && ((DiaryFood) item).dateOpened < day)) { 
      iterator.remove(); 
    } 
} 
+0

Это было очень полезно, спасибо! – Soi

1

Использование instanceof и отливка может выглядеть просто с парой классов, но представьте себе, если у вас было 10 Food подклассов, каждый с собственной логикой удаления.

Добавление метода getDateOpened() к Food класса, что делает его вернуть null в классах, которые не имеют атрибут dateOpened добавляет ненужную сложность к интерфейсу.Пользователи должны знать, что для некоторых подклассов Food этот метод вернет действительное значение, а для других - нет. Он также недостаточно масштабируется по числу подклассов.

Один из вариантов, который является типичным, заключается в том, чтобы переместить логику, которая решает, что какой-либо тип пищи должен быть удален для этого типа.

Например, создать метод shouldBeRemoved(int) в Food классе:

public abstract class Food { 
    public boolean shouldBeRemoved(int day) { 
     return this.useDate < day; 
    } 
} 

И затем переопределить его в DiaryFood классе, принимая атрибут dateOpened во внимание:

public class DiaryFood extends Food { 
    @Override 
    public boolean shouldBeRemoved(int day) { 
     return this.getUseDate() < day || this.dateOpened < day; 
    } 
} 

Таким образом, в Shelf класс вы можете сделать:

public void cleanShelf(int day) { 
    ArrayList<Food> foodToRemove = new ArrayList<Food>(); 
    for (int i = 0; i < food.size(); i++) { 
     if (food.get(i).shouldBeRemoved(day)) { 
      foodToRemove.add(food.get(i)); 
     } 
    } 
    food.removeAll(foodToRemove); 
} 

Если вы используете Java 8, этот последний метод может быть простым:

public void cleanShelf(int day) { 
    food.removeIf(food -> food.shouldBeRemoved(day)); 
} 
+0

Две вещи: DiaryFood не может использовать 'this.useDate', поскольку он является закрытым в родительском классе. И, я думаю, вы должны упомянуть, что это, в некотором роде, усложняет ситуацию, потому что теперь это не шельф, который решает: «Эй, я больше не хочу эту пищу!», Но это еда, которая говорит «Эй, я больше не вписывайтесь! ». В зависимости от проекта, над которым вы работаете, это может не быть проблемой вообще или действительно, действительно большой. – Adowrath

Смежные вопросы