Допустим, у нас есть программа, которая содержит такие классы:
public interface AbstractItem {
}
public SharpItem implements AbstractItem {
}
public BluntItem implements AbstractItem {
}
public interface AbstractToolbox {
//well the problem starts here...
public List<AbstractItem> getItems();
}
public ExpensiveToolbox implements AbstractToolbox {
private List<SharpItem> items = new ArrayList()<SharpItems>;
public List<SharpItem> getItems() { return this.items; }
}
public CheapTooblox implements AbstractToolbox {
private List<BluntItem> items = new ArrayList()<BluntItem>;
public List<BluntItem> getItems() { return this.items; }
}
Легко, верно?Давайте предположим, что теперь мы хотим создать такой метод (в некотором случайном классе):
public void doImportantStuff(AbstractToolbox toolbox) {
//important stuff!
//this obviously won't work
List<AbstractToolbox> items = toolbox.getItems();
//do some stuffwith all items
}
Теперь проблема заключается в том, что в Java-коллекциях с обобщениями нет ковариантности (надеюсь, это терминищу) и я не могу присвоить ArrayList<ExpensiveToolbox>
List<AbstractToolbox>
.Единственное решение, которое я вижу здесь, - это продублировать код и создать версию для каждого типа, но это, очевидно, будет отстой (что если бы у нас было больше классов, реализующих AbstractToolbox с разными списками?).О, очевидно, вторым решением было бы отказаться от дженериков и создать обычный список, но разве это хорошая практика?
Существуют ли какие-либо шаблоны / методы проектирования для решения таких проблем?
@ Edit: ok, так что я не могу быть достаточно точным.Я хочу, чтобы все классы, которые расширяют AbstractToolbox, имели список определенных классов, которые расширяют AbstractItem, а затем мне нужен метод, который будет принимать AbstractToolbox в качестве параметра и делать что-то с элементами в его списке (используя классы, которые будут определены вAbstractItem, чтобы все элементы каждого возможного списка действительно имели их).