Вопрос-ответ

"Program to an interface". What does it mean? [duplicate]

"Программа для интерфейса". Что это значит?

Возможно дублирование:

Что значит "программа для интерфейса”?


Я продолжаю сталкиваться с этим термином:


Программа для интерфейса.


Что именно это означает? Хотелось бы получить реальный сценарий проектирования.

Переведено автоматически
Ответ 1

Проще говоря, вместо того, чтобы писать свои классы таким образом, который говорит


Я зависю от этого конкретного класса в выполнении своей работы


вы пишете это таким образом, чтобы сказать


Я завишу от любого класса, который делает это для выполнения моей работы.


Первый пример представляет класс, выполнение работы которого зависит от конкретной реализации. По сути, это не очень гибко.

Второй пример представляет класс, записанный для интерфейса. Ему все равно, какой конкретный объект вы используете, ему важно только, чтобы он реализовывал определенное поведение. Это делает класс намного более гибким, поскольку ему может быть предоставлено любое количество конкретных реализаций для выполнения его работы.

В качестве примера, определенному классу может потребоваться выполнить некоторое ведение журнала. Если вы пишете класс так, чтобы он зависел от TextFileLogger , класс навсегда вынужден записывать свои записи журнала в текстовый файл. Если вы хотите изменить поведение ведения журнала, вы должны изменить сам класс. Класс тесно связан со своим регистратором.

Однако, если вы напишете класс так, чтобы он зависел от интерфейса ILogger, а затем предоставите классу TextFileLogger , вы добьетесь того же, но с дополнительным преимуществом в виде гораздо большей гибкости. Вы можете предоставить любой другой тип ILogger по желанию, не изменяя сам класс. Класс и его logger теперь слабо связаны, и ваш класс намного более гибкий.

Ответ 2

Интерфейс - это набор связанных методов, который содержит только сигнатуры этих методов, а не фактическую реализацию.
Если класс реализует интерфейс (class Car implements IDrivable), он должен предоставить код для всех сигнатур, определенных в интерфейсе.

Базовый пример:
Вы должны использовать классы Car и Bike. Оба реализуют интерфейс IDrivable:

interface IDrivable 
{
void accelerate();
void brake();
}

class Car implements IDrivable 
{
void accelerate()
{ System.out.println("Vroom"); }

void brake()
{ System.out.println("Queeeeek");}
}

class Bike implements IDrivable 
{
void accelerate()
{ System.out.println("Rattle, Rattle, ..."); }

void brake()
{ System.out.println("..."); }
}

Теперь давайте предположим, что у вас есть коллекция объектов, которые все "управляемы" (все их классы реализуют IDrivable):

List<IDrivable> vehicleList = new ArrayList<IDrivable>();
list.add(new Car());
list.add(new Car());
list.add(new Bike());
list.add(new Car());
list.add(new Bike());
list.add(new Bike());

Если вы теперь хотите выполнить цикл по этой коллекции, вы можете положиться на тот факт, что каждый объект в этой коллекции реализует accelerate():

for(IDrivable vehicle: vehicleList) 
{
vehicle.accelerate(); //this could be a bike or a car, or anything that implements IDrivable
}

Вызывая этот метод интерфейса, вы программируете не для реализации, а для интерфейса - контракта, который гарантирует, что цель вызова реализует определенную функциональность.

Такого же поведения можно было бы достичь с помощью наследования, но вывод из общего базового класса приводит к тесной связи, которой можно избежать с помощью интерфейсов.

Ответ 3

Примеры из реального мира - applenty. Один из них:

Для JDBC вы используете интерфейс java.sql.Connection. Однако каждый драйвер JDBC предоставляет свою собственную реализацию Connection. Вам не нужно ничего знать о конкретной реализации, потому что она соответствует Connection интерфейсу.

Другой вариант взят из java collections framework. Существует java.util.Collection интерфейс, который определяет size, add и remove методы (среди многих других). Таким образом, вы можете использовать все типы коллекций взаимозаменяемо. Допустим, у вас есть следующее:

public float calculateCoefficient(Collection collection) {
return collection.size() * something / somethingElse;
}

И два других метода, которые вызывают этот. Один из других методов использует a LinkedList потому что он более эффективен для своих целей, а другой использует a TreeSet.

Поскольку и LinkedList, и TreeSet реализуют Collection интерфейс, вы можете использовать только один метод для выполнения вычисления коэффициента. Нет необходимости дублировать ваш код.

И вот появляется "программа для интерфейса" - вам все равно, как именно реализован size() метод, вы знаете, что он должен возвращать размер коллекции - т. Е. вы запрограммировали для Collection интерфейса, а не для LinkedList и TreeSet в частности.

Но мой совет - найдите что-нибудь почитать - возможно, книгу (например, "Мышление на Java"), - где концепция объясняется подробно.

Ответ 4

Полиморфизм зависит от программирования для интерфейса, а не от реализации.

Манипулирование объектами исключительно в терминах интерфейса, определяемого абстрактными классами, имеет два преимущества:


  1. Клиенты остаются в неведении о конкретных типах объектов, которые они используют, до тех пор, пока объекты соответствуют интерфейсу, который ожидают клиенты.

  2. Клиенты остаются в неведении о классах, реализующих эти объекты. Клиенты знают только об абстрактных классах, определяющих интерфейс.

Это настолько сильно уменьшает зависимости реализации между подсистемами, что приводит к такому принципу программирования для интерфейса.

Смотрите Шаблон заводского метода для дальнейшего обоснования этого дизайна.

Источник: "Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения" от G.O.F.

Смотрите также: Заводской шаблон. Когда использовать заводские методы?

java oop