может кто-нибудь сказать мне, почему рекомендуется использовать интерфейс в качестве типа данных??
Я пытаюсь понять лучшие практики проектирования надежных и удобных в обслуживании программных систем на Java. Одна из концепций, с которой я столкнулся, — это рекомендация использовать интерфейсы в качестве типов данных вместо базовых классов. Однако я изо всех сил пытаюсь понять причину такого подхода.
Насколько я понимаю, использование интерфейса в качестве типа данных обеспечивает большую гибкость и полиморфизм, поскольку позволяет мне работать с любым классом, реализующим интерфейс. Но я не уверен, что это единственная причина, и мне хотелось бы узнать больше о преимуществах такого подхода.
Может ли кто-нибудь объяснить, почему использование интерфейсов в качестве типов данных предпочтительнее использования базовых классов? Как этот подход улучшает качество кода и обеспечивает соблюдение принципов объектно-ориентированного проектирования SOLID?
Я пытался исследовать эту тему, но мне до сих пор неясны преимущества использования интерфейсов в качестве типов данных. Я был бы признателен за любые идеи или примеры, которые помогут мне лучше понять эту концепцию.
Работа с интерфейсами заставляет думать не о поведении, а о общении. Примером может служить интерфейс CRUD, который вы можете использовать сначала HashMap
, а затем заменить реализацией, которая фактически подключается к базе данных. Другой момент заключается в том, что замена компонентов (если все сделано правильно, с использованием Фабрик и других шаблонов) позволяет заменять компоненты с небольшими изменениями или вообще без них. Взгляните на класс ServiceLoader
, который поможет вам переключаться между компонентами, передавая их как системные свойства.
Разве подобные вещи не задавались и не отвечали на них много раз раньше? Где вы показываете свои исследования по этому поводу в своем вопросе?
В приведенном ниже примере list1
или list2
можно использовать в качестве аргумента метода отображения. Если бы вы явно использовали типы классов, это не сработало бы, поскольку вам потребовалось бы два метода: один для ArrayList
и один для LinkedList
.
Это позволяет лучше поддерживать ваш код без необходимости внесения нескольких изменений, если вы выберете другую реализацию какого-либо класса, в данном случае ArrayList
или LinkedList
.
List<Integer> list1 = new ArrayList<>();
List<Integer> list2 = new LinkedList<>();
public <T> T void display(List<T> list) {
System.out.printnln(list);
}
Хотя это не имеет отношения к вашему конкретному вопросу, я использовал дженерики, поэтому List<String> list3
также может быть аргументом для display
.
Далее следует более fun
пример. Обратите внимание, что я могу назначить каждый класс «животное» списку MealTime
, поскольку каждый из них реализует этот интерфейс. В противном случае эти классы можно было бы назначить только List<Object>
.
interface MealTime {
public String feedMe();
}
class Lion implements MealTime {
private String food;
public Lion(String food) {
this.food = food;
}
public String feedMe() {
return food;
}
}
class Koala implements MealTime {
private String food;
public Koala(String food) {
this.food = food;
}
public String feedMe() {
return food;
}
}
public static void main(String[] args) {
List<MealTime> zoo = List.of(
new Koala("Eucalyptus leaves"),
new Lion("Eland meat"));
FeedTheAnimals(zoo);
}
public static void FeedTheAnimals(List<MealTime> zoo) {
for (MealTime animal : zoo) {
System.out.println("I am feeding the "
+ animal.getClass().getSimpleName() + " some " +
animal.feedMe());
}
}
принты
I am feeding the Koala some Eucalyptus leaves
I am feeding the Lion some Eland meat
как вы написали, «это позволяет мне работать с любым классом, реализующим интерфейс» - больше добавить нечего