Вариант 1 считается программированием для интерфейса, а вариант 2 — программированием для реализации. Последнее иногда необходимо, но первое дает вам возможность легко переключаться между реализациями, гарантируя, что вы не будете зависеть от методов, предоставляемых конкретной реализацией.
Кроме того, если вы создаете методы, которым нужна только функциональность, предоставляемая интерфейсом, то они должны быть объявлены как требующие интерфейса, чтобы им мог быть передан любой объект, реализующий интерфейс. Это расширяет возможности повторного использования API. Например:
// This can be called passing any List
public int countItems(List lst, Filter flt) {
// iterate list, apply filter, and count matching objects
}
// This can called passing only an ArrayList, an unnecessary limitation in this case
public int countItems(ArrayList lst, Filter flt) {
// iterate list, apply filter, and count matching objects
}
Тем не менее, для некоторых интерфейсов существуют скрытые ловушки, зависящие от реализации (по крайней мере, в Java). Пример этого в List.get(int)
; если у вас есть ArrayList
это эффективно, но для LinkedList
это не так. Если список очень большой, разница может быть существенной, особенно для плохо продуманной конструкции, такой как этот цикл:
for(int xa=0,len=list.length; xa<len; xa++) {
Object obj=list.get(xa);
obj.doSomething();
}
который имеет ужасную производительность для больших связанных списков, поскольку список должен проходить с самого начала для каждого get(xa)
.
person
Lawrence Dol
schedule
16.03.2010