“Программа к интерфейсу”.Что это значит? [дубликат]

Возможный дубликат:
Что означает к “программе к интерфейсу”?

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

Программа к интерфейсу.

Что точно это означает? Реальный сценарий дизайна высоко ценился бы.

35
задан Community 23 May 2017 в 11:46
поделиться

8 ответов

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

, я завишу от этого специфического класса, чтобы делать мою работу

, вы пишете его так, чтобы было написано

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

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

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

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

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

76
ответ дан 27 November 2019 в 06:27
поделиться

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

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

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

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

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

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

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

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

.
8
ответ дан 27 November 2019 в 06:27
поделиться

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

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

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

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

Смотрите шаблон Factory Method pattern для дальнейшего рассуждения об этом шаблоне.

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

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

8
ответ дан 27 November 2019 в 06:27
поделиться

У каждого объекта есть открытый интерфейс. Коллекция имеет Add, Remove, At и др. Сокет может иметь Send, Receive, Close и т.д.

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

Обе эти вещи очевидны, однако, что несколько менее очевидно. ...

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

Если вы доведете его до крайности, вы будете писать код только против Collection и т.д. (а не против ArrayList). Более практично, просто убедитесь, что вы можете поменять что-то концептуально идентичное, не взломав свой код.

Чтобы забить пример с Collection: у вас есть коллекция чего-то, на самом деле вы используете ArrayList, потому что почему бы и нет . Вы должны убедиться, что ваш код не сломается, если, скажем, в будущем вы будете использовать LinkedList.

.
4
ответ дан 27 November 2019 в 06:27
поделиться

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

Это также означает, что вам не нужно заботиться о внутренностях кода, от которого вы зависите, пока интерфейс остаётся прежним, ваш код безопасен (ну, более или менее...)

Технически есть более мелкие детали, такие как, например, концепции языка, называемые "интерфейсами" в Java.

Если вы хотите узнать больше, вы можете спросить, что означает "Реализация интерфейса"...

.
3
ответ дан 27 November 2019 в 06:27
поделиться

В основном это означает, что единственная часть библиотеки, которую вы собираетесь использовать, должна опираться на API (Application programming interface) и что вы не должны основывать свое приложение на конкретной реализации библиотеки.

например. Предположим, что у вас есть библиотека, которая дает вам стек. Класс дает вам пару методов. Допустим, push, pop, isempty и top. Вы должны написать заявление, полагаясь только на них. Одним из способов нарушить это будет заглянуть внутрь и узнать, что стек реализован с использованием массива какого-то типа, так что если вы всплываете из пустого стека, вы получите какое-нибудь исключение из индекса, а затем поймаете его, вместо того, чтобы полагаться на метод isempty, который предоставляет класс. Первый подход был бы неудачным, если бы провайдер библиотек перешел от использования массива к использованию какого-то списка, в то время как второй все равно работал бы, предполагая, что провайдер поддерживает свое API в рабочем состоянии.

2
ответ дан 27 November 2019 в 06:27
поделиться

Думаю, это одна из мантр Эриха Гаммы. Я не могу найти первый раз, когда он описал ее (до книги GOF), но вы можете увидеть, как она обсуждалась в интервью: http://www.artima.com/lejava/articles/designprinciples.html

2
ответ дан 27 November 2019 в 06:27
поделиться

Интерфейс представляет собой набор взаимосвязанных методов, который содержит только сигнатуры этих методов, а не фактическую реализацию.
Если класс реализует интерфейс (class Car реализует 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());

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

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

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

19
ответ дан 27 November 2019 в 06:27
поделиться
Другие вопросы по тегам:

Похожие вопросы: