Столкнулся тут с такими принципами:
— метод должен принимать параметры как можно более общего типа
— метод должен возвращать объект как можно более конкретного класса
Первый принцип, можно сказать, классика и позволяет избегать большой связности. Со вторым же у меня трудности с пониманием приемуществ такого подхода(недостаток в виде большей связности весьма очевиден).
Рассмотрим на примере (здесь и далее Java, хотя это особого значения вроде как и не имеет)
'Классический' вид:
List<String> getNames(Long parentId, List<String> params) {
List<String> result = new ArrayList<String>(20); // нам доподлинно известно что будет не больше 20 элементов
// заполнение result
return result;
}
'Конкретный' вид:
ArrayList<String> getNames(Long parentId, List<String> params) {
List<String> result = new ArrayList<String>(20); // нам доподлинно известно что будет не больше 20 элементов
// заполнение result
return result;
}
Модификатор доступа я умышленно опустил, чтобы остался повод для дискуссии применимо ли это для public или может только private методов. На мой взгляд общедоступные методы не должны ни в коем случае быть 'конкретными'.
Дальнейшие примеры и случаи для 'конкретного' вида.
Теперь вариант кода когда нам все равно конкретный класс или интерфейс в сигнатуре метода, 'не опасный':
void method1() {
List<String> names = getNames(...);
}
void method2(List<String> names) {
//делаем что-то
}
void method3() {
method3(getNames(...));
}
Код 'средней опасноти':
void method1() {
ArrayList<String> names = getNames(...);
// делаем что-то, но за рамки интерфейса List не выходим. Но зачем тогда объявление names как ArrayList :) ?
}
Ну и на закуску, 'опасный' код:
void method1() {
ArrayList<String> names = getNames(...);
// делаем что-то
names.trimToSize(); // специфический для ArrayList метод
// делаем что-то
}
И вот наступает момент, когда нам приходится менять в getName ArrayList на LinkedList.
— В случае 'не опасного' кода ничего менять не надо. Но тогда вопрос зачем в сигнатуре метода указывать конкретный класс?
— 'среднеопасный' код: меняем в коде имя одного класса на другое и больше ничего не надо делать. И опять вопрос: зачем и почему такое может понадобиться, если с интерфейсами был бы точно такой код?
— 'опасный код': в этом случае мы отгребаем за связность и нам приходится не только менять тип переменной, но и переписывать логику. Тут я могу придумать для чего так можно было сделать: например, для оптимизации когда известно, что конкретная рализация в данном случае будет эффективнее намного другой.
Резюмируя все примеры и мысли:
Возвращать конкретный класс, а не интерфейс в общем случае скорее вредно, чем полезно и применять такой принцип для всех методов лучше не стоит.
Не упустил ли я какую-то деталь, которая доказывает полезность 'конкретного' принципа?