Что значит программировать интерфейс?

Я видел это несколько раз, и я не понимаю, что это значит. Когда и зачем вы это сделали?

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

Это так, если бы вы сделали:

IInterface classRef = new ObjectWhatever()

Вы можете использовать любой класс, реализующий IInterface? Когда вам нужно это сделать? Единственное, о чем я могу думать, - это если у вас есть метод и вы не уверены, какой объект будет передан, кроме того, что он реализует IInterface. Я не могу представить, как часто вам нужно будет это делать.

Кроме того, как вы могли бы написать метод, который принимает объект, реализующий интерфейс? Это возможно?


person Damien    schedule 21.12.2008    source источник
comment
Если вы помните, и ваша программа должна быть оптимальной, прямо перед компиляцией вы можете поменять местами объявление интерфейса на фактическую реализацию. Поскольку использование интерфейса добавляет уровень косвенности, который снижает производительность. Распространите свой код, запрограммированный на интерфейсы, хотя ...   -  person Ande Turner    schedule 21.12.2008
comment
@ Анде Тернер: плохой совет. 1). ваша программа должна быть оптимальной - это не повод отказываться от интерфейсов! Затем вы говорите «Распространить свой код, запрограммированный на интерфейсы», хотя ... так что вы сообщаете, что с учетом требования (1) вы затем выпускаете неоптимальный код?!?   -  person Mitch Wheat    schedule 21.12.2008
comment
Большинство ответов здесь не совсем правильные. Это вовсе не означает и даже не подразумевает использование ключевого слова interface. Интерфейс - это спецификация того, как что-то использовать, синоним контракта (найдите его). Отдельно от этого стоит реализация - то, как выполняется этот контракт. Запрограммируйте только гарантии метода / типа, чтобы при изменении метода / типа способом, который все еще подчиняется контракту, он не нарушал код, использующий его.   -  person jyoungdev    schedule 27.04.2012
comment
@ apollodude217, что на самом деле лучший ответ на всей странице. По крайней мере, по вопросу в заголовке, поскольку здесь есть как минимум 3 совершенно разных вопроса ...   -  person Andrew Spencer    schedule 02.05.2012
comment
Основная проблема с подобными вопросами заключается в том, что они предполагают, что программирование интерфейса означает обертывание всего в абстрактный интерфейс, что глупо, если учесть, что этот термин предшествует концепции абстрактных интерфейсов в стиле Java.   -  person Jonathan Allen    schedule 19.07.2012
comment
В основном это делается с помощью COM. Где вы обрабатываете объект, не зная класса, а только то, какой интерфейс он поддерживает.   -  person Jeroen van Langen    schedule 15.08.2013
comment
Это просто модное слово для обратного вызова. Вот и все. Все это означает, что вы что-то делаете (например, получаете информацию из сети или делаете расчет). Эта другая вещь в конечном итоге вызовет вашу функцию, чтобы сообщить вам результат. Верно? Поэтому вам нужно как-то указать имя этой функции (функция обратного вызова). Интерфейс! просто указывает имя этой функции. Это все, не более того.   -  person Fattie    schedule 08.12.2016
comment
Классический List lst = new ArrayList(); просто означает, что вы ограничиваете, какие функции для созданного объекта вам доступны, что совершенно глупо. Эта странная конструкция продолжает распространяться учителями и книгами Java без всякой мыслимой причины.   -  person Nyerguds    schedule 06.01.2017
comment
@Damien, не объединяйте этот вопрос с дополнительными вопросами. ТАК - это 1 вопрос на тематический сайт. Лучше задавать отдельные вопросы и ссылаться на этот, если он актуален.   -  person Disillusioned    schedule 08.01.2017


Ответы (32)


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

Когда я впервые начал знакомиться с интерфейсами, меня тоже смутила их актуальность. Я не понимал, зачем они вам нужны. Если мы используем такой язык, как Java или C #, у нас уже есть наследование, и я рассматривал интерфейсы как более слабую форму наследования и подумал: «Зачем беспокоиться?» В каком-то смысле я был прав, вы можете думать об интерфейсах как о некой слабой форме наследования, но, помимо этого, я наконец понял их использование в качестве языковой конструкции, думая о них как о средстве классификации общих черт или поведения, которые проявляются потенциально много не связанных классов объектов.

Например, скажем, у вас есть игра для SIM-карты и у вас есть следующие классы:

class HouseFly inherits Insect {
    void FlyAroundYourHead(){}
    void LandOnThings(){}
}

class Telemarketer inherits Person {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}
}

Ясно, что эти два объекта не имеют ничего общего с точки зрения прямого наследования. Но можно сказать, что они оба раздражают.

Допустим, в нашей игре должна быть какая-то случайная вещь, которая раздражает игрока, когда он ужинает. Это может быть HouseFly, Telemarketer или и то, и другое - но как сделать это с помощью одной функции? И как вы попросите разные типы объектов одинаково «делать то, что их раздражает»?

Ключ к пониманию состоит в том, что и Telemarketer, и HouseFly имеют общее, слабо интерпретируемое поведение, даже если они не похожи друг на друга с точки зрения их моделирования. Итак, давайте создадим интерфейс, который оба могут реализовать:

interface IPest {
    void BeAnnoying();
}

class HouseFly inherits Insect implements IPest {
    void FlyAroundYourHead(){}
    void LandOnThings(){}

    void BeAnnoying() {
        FlyAroundYourHead();
        LandOnThings();
    }
}

class Telemarketer inherits Person implements IPest {
    void CallDuringDinner(){}
    void ContinueTalkingWhenYouSayNo(){}

    void BeAnnoying() {
        CallDuringDinner();
        ContinueTalkingWhenYouSayNo();
    }
}

Теперь у нас есть два класса, каждый из которых может по-своему раздражать. И им не обязательно быть производными от одного и того же базового класса и иметь общие неотъемлемые характеристики - им просто нужно выполнять контракт IPest - этот контракт прост. Вам просто нужно BeAnnoying. В связи с этим можно смоделировать следующее:

class DiningRoom {

    DiningRoom(Person[] diningPeople, IPest[] pests) { ... }

    void ServeDinner() {
        when diningPeople are eating,

        foreach pest in pests
        pest.BeAnnoying();
    }
}

Здесь у нас есть столовая, которая принимает множество посетителей и множество вредителей - обратите внимание на использование интерфейса. Это означает, что в нашем маленьком мире член массива pests может быть объектом Telemarketer или объектом HouseFly.

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

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

person Peter Meyer    schedule 21.12.2008
comment
Еще одна вещь, которую следует учитывать, - это то, что в некоторых случаях может быть полезно иметь интерфейс для вещей, которые могут раздражать, и иметь множество объектов, реализующих BeAnnoying как запретную; этот интерфейс может существовать вместо или в дополнение к интерфейсу для вещей, которые раздражают (если существуют оба интерфейса, вещи, которые являются раздражающим интерфейсом, должны унаследовать от того, что может быть раздражающий интерфейс). Недостатком использования таких интерфейсов является то, что реализации могут быть обременены реализацией раздражающего количества методов-заглушек. Преимущество в том, что ... - person supercat; 20.07.2012
comment
... часто быстрее вызывать метод-заглушку без нужды, чем определять, следует ли вызывать метод. Это одна из причин, по которой IEnumerator<T> наследует IDisposable. В подавляющем большинстве случаев для потребителя счетчика будет дешевле безоговорочно вызвать Dispose на нем, чем для потребителя проверить, нужен ли Dispose вызов. Жаль, что ни .net, ни Java не позволяют указывать реализации по умолчанию для методов интерфейса, поскольку во многих ситуациях интерфейсы могут выиграть от «необязательных» методов, где были бы ... - person supercat; 20.07.2012
comment
... четкое разумное поведение по умолчанию (иногда ничего не делать, иногда генерировать исключение и часто фиксированным образом вызывать какой-либо статический метод или какой-либо другой член интерфейса); такая функция сделала бы гораздо более практичным наличие большего количества типов, реализующих возможно интерфейсы, уменьшая необходимость проверки типов и приведения типов во время выполнения. - person supercat; 20.07.2012
comment
Почему у класса HouseFly все еще есть абстрактные методы? - person BAD_SEED; 10.02.2014
comment
Эти методы не предназначены для представления абстрактных методов - их реализация не имеет отношения к вопросу, касающемуся интерфейсов. - person Peter Meyer; 18.02.2014
comment
Инкапсуляция поведений, таких как IPest, известна как шаблон стратегии на тот случай, если кто-то заинтересован в получении дополнительных материалов по этой теме ... - person nckbrz; 09.03.2014
comment
Интересно, что вы не указываете, что, поскольку объекты в IPest[] являются ссылками IPest, вы можете вызывать BeAnnoying(), потому что у них есть этот метод, в то время как вы не можете вызывать другие методы без приведения. Однако для каждого объекта будет вызываться индивидуальный BeAnnoying() метод. - person D. Ben Knoble; 26.05.2015
comment
Означает ли это, что при выполнении кода в цикле foreach будут вызываться оба метода Be.Annoying()? - person user3293145; 16.07.2015
comment
Будет вызван только метод BeAnnoying() класса, реализующего или реализующего интерфейс. - person Peter Meyer; 28.07.2015
comment
Очень хорошее объяснение ... Мне просто нужно сказать это здесь: я никогда не слышал, чтобы интерфейсы были своего рода свободным механизмом наследования, но вместо этого я знаю, что наследование используется как плохой механизм для определения интерфейсов ( например, в обычном Python вы делаете это постоянно). - person Carlos H Romano; 09.08.2015
comment
Я не уверен, является ли несвязанность TeleMarketer и HouseFly ключом к использованию интерфейсов. Даже если они связаны, ситуация по-прежнему требует интерфейсов с учетом ограничений, связанных с базовыми классами. Ключевым моментом здесь является поведение. Существует концептуальная разница между интерфейсом и абстрактным классом, где первый используется, когда вы хотите передать , имеет поведение (в отличие от последнего, который строго является). - person nawfal; 10.11.2015
comment
хотите больше о Программе, а не о ее реализации - как насчет этой части? FlyAroundYourHead() слишком специфичен и относится к реализованному элементу? То же самое с .bark() и .meow(), которые являются программой для реализации - потому что они слишком сильно привязаны к Dog и Cat. Если программировать интерфейс, он должен быть .giveSound() То есть достаточно общим, чтобы не зависеть от конкретной реализации (или определенного подкласса). - person nonopolarity; 01.01.2016
comment
Другой дизайн для ситуации: события здесь раздражают, и у каждого человека должны быть свои собственные раздражающие события, которые, когда происходят во время обеда, сводят его с ума. - person Lost Koder; 18.11.2016
comment
Этот пример ответа больше похож на инверсию зависимостей (которая также программируется для интерфейсов), чем на пример программирования для интерфейсов. Я хотел бы увидеть полезный пример программирования интерфейсов, который также не включает инверсию зависимостей. - person Shaun Luttin; 03.07.2017
comment
Конечно, это отличный способ объяснить, почему интерфейсы полезны, однако это действительно не ответ на главный вопрос (этот ответ stackoverflow.com/a/383982/9868445 в этом отношении намного лучше) - person aderchox; 15.09.2018
comment
Плюс один за отношения между телемаркетологом и комнатной мухой. - person MC Emperor; 22.09.2018
comment
a means of classifying common traits or behaviors that were exhibited by potentially many non-related classes of objects это совершенно точно! Иногда не очевидно, что два класса (или более) имеют общую связь. Хороший ответ :) - person James; 02.06.2019
comment
Это единственный лучший ответ, который я когда-либо видел при переполнении стека. - person Adam Hughes; 12.07.2020
comment
Вы могли бы добавить, что этот дизайн достаточно слабо связан между DiningRoom и различными вредителями, что вы можете вводить новых вредителей (подумайте class Covid19 implements IPest {...};!), Которых даже не существовали, когда был написан класс DiningRoom! < / b> Вам не только не нужно менять Столовую, вам даже не нужно перекомпилировать ее! Пригодится для тестов и больших проектов. - person Peter - Reinstate Monica; 26.03.2021

Конкретный пример, который я привел студентам, заключается в том, что они должны писать

List myList = new ArrayList(); // programming to the List interface

вместо того

ArrayList myList = new ArrayList(); // this is bad

Они выглядят точно так же в короткой программе, но если вы продолжите использовать myList 100 раз в своей программе, вы начнете видеть разницу. Первое объявление гарантирует, что вы вызываете только методы myList, которые определены интерфейсом List (поэтому никаких ArrayList конкретных методов). Если вы запрограммировали интерфейс таким образом, позже вы можете решить, что вам действительно нужно

List myList = new TreeList();

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

Преимущества еще более очевидны (я думаю), когда вы говорите о параметрах метода и возвращаемых значениях. Возьмем, к примеру, следующее:

public ArrayList doSomething(HashMap map);

Это объявление метода связывает вас с двумя конкретными реализациями (ArrayList и HashMap). Как только этот метод вызывается из другого кода, любые изменения этих типов, вероятно, означают, что вам также придется изменить вызывающий код. Лучше бы программировать на интерфейсы.

public List doSomething(Map map);

Теперь не имеет значения, какой тип List вы вернете или какой Map будет передан в качестве параметра. Изменения, которые вы делаете внутри метода doSomething, не заставят вас изменить вызывающий код.

person Bill the Lizard    schedule 21.12.2008
comment
Комментарии не подлежат расширенному обсуждению; этот разговор был перешел в чат. - person ; 12.01.2019
comment
У меня есть вопрос о причине, о которой вы упомянули. Первое объявление гарантирует, что вы вызываете только те методы в myList, которые определены интерфейсом List (поэтому никаких методов, специфичных для ArrayList). Если вы запрограммировали интерфейс таким образом, позже вы можете решить, что вам действительно нужен List myList = new TreeList (); и вам нужно только изменить свой код в одном месте. Возможно, я неправильно понял, мне интересно, почему вам нужно изменить ArrayList на TreeList, если вы хотите гарантировать, что вы вызываете только методы в myList? - person user3014901; 23.10.2019
comment
@ user3014901 Существует множество причин, по которым вы можете захотеть изменить тип используемого списка. Например, производительность поиска может быть выше. Дело в том, что если вы программируете в интерфейсе List, это упрощает изменение кода на другую реализацию позже. - person Bill the Lizard; 24.10.2019

Программирование интерфейса говорит: «Мне нужна эта функциональность, и мне все равно, откуда она взялась».

Рассмотрим (в Java) интерфейс List в сравнении с конкретными классами ArrayList и LinkedList. Если все, что меня волнует, это то, что у меня есть структура данных, содержащая несколько элементов данных, к которым я должен получить доступ через итерацию, я бы выбрал List (а это в 99% случаев). Если я знаю, что мне нужна постоянная вставка / удаление с любого конца списка, я могу выбрать конкретную реализацию LinkedList (или, что более вероятно, использовать Queue interface). Если я знаю, что мне нужен произвольный доступ по индексу, я бы выбрал конкретный класс ArrayList.

person kdgregory    schedule 21.12.2008
comment
полностью согласен, то есть независимость между тем, что делается, и тем, как это делается. Разделив систему на независимые компоненты, вы получите систему, которая проста и может использоваться повторно (см. Simple Made Easy создателем Clojure) - person beluchin; 29.12.2013

Программирование интерфейса не имеет абсолютно ничего общего с абстрактными интерфейсами, как мы видим в Java или .NET. Это даже не концепция ООП.

Это означает, что не стоит возиться с внутренним устройством объекта или структуры данных. Используйте абстрактный программный интерфейс или API для взаимодействия с вашими данными. В Java или C # это означает использование общедоступных свойств и методов вместо доступа к необработанным полям. Для C это означает использование функций вместо необработанных указателей.

РЕДАКТИРОВАТЬ: А с базами данных это означает использование представлений и хранимых процедур вместо прямого доступа к таблицам.

person Jonathan Allen    schedule 19.07.2012
comment
Лучший ответ. Гамма дает аналогичное объяснение здесь: artima.com/lejava/articles/designprinciples.html (см. стр. 2). Он ссылается на концепцию объектно-ориентированного программирования, но вы правы: она намного шире. - person Sylvain Rodrigue; 13.03.2015

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

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

РЕДАКТИРОВАТЬ: Ниже приводится ссылка на статью, в которой Эрих Гамма обсуждает свою цитату: «Программа для интерфейса, а не реализация».

http://www.artima.com/lejava/articles/designprinciples.html

person tvanfosson    schedule 21.12.2008
comment
Пожалуйста, прочтите еще раз это интервью: Gamma, конечно же, говорила о концепции интерфейса OO, а не о JAVA или специальном классе C # (ISomething). Проблема в том, что большинство людей, хотя он говорил о ключевом слове, теперь у нас много ненужных интерфейсов (ISomething). - person Sylvain Rodrigue; 13.03.2015
comment
Очень хорошее интервью. Будьте осторожны с будущими читателями, в интервью четыре страницы. Я почти закрывал браузер, прежде чем его увидел. - person Ad Infinitum; 21.04.2017

Вы должны изучить Inversion of Control:

В таком сценарии вы бы не написали это:

IInterface classRef = new ObjectWhatever();

Вы бы написали что-то вроде этого:

IInterface classRef = container.Resolve<IInterface>();

Это приведет к настройке на основе правил в объекте container и построит для вас фактический объект, которым может быть ObjectWhatever. Важно то, что вы можете заменить это правило чем-то, что вообще использует другой тип объекта, и ваш код все равно будет работать.

Если мы оставим IoC вне таблицы, вы можете написать код, который знает, что он может взаимодействовать с объектом , который делает что-то конкретное, но не о том, какой тип объекта или как он это делает.

Это пригодится при передаче параметров.

Что касается вашего вопроса в скобках «Кроме того, как вы могли бы написать метод, который принимает объект, реализующий интерфейс? Возможно ли это?», В C # вы просто использовали бы тип интерфейса для типа параметра, например:

public void DoSomethingToAnObject(IInterface whatever) { ... }

Это прямо относится к «разговору с объектом, который делает что-то конкретное». Определенный выше метод знает, чего ожидать от объекта, что он реализует все в IInterface, но его не волнует, какой это тип объекта, а только то, что он придерживается контракта, а именно интерфейса.

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

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

Приведу конкретный пример.

У нас есть специально разработанная система перевода для оконных форм. Эта система просматривает элементы управления в форме и переводит текст в каждом из них. Система знает, как обрабатывать базовые элементы управления, такие как свойство-type-of-control-that-has-a-Text, и аналогичные базовые вещи, но для чего-то базового ей не хватает.

Теперь, поскольку элементы управления наследуются от предопределенных классов, которые мы не контролируем, мы могли бы сделать одно из трех:

  1. Создайте поддержку нашей системы перевода, чтобы точно определять, с каким типом управления она работает, и переводить правильные биты (кошмар обслуживания)
  2. Встроить поддержку в базовые классы (невозможно, поскольку все элементы управления наследуются от разных предопределенных классов)
  3. Добавить поддержку интерфейса

Итак, мы сделали № 3. Все наши элементы управления реализуют ILocalizable, который представляет собой интерфейс, который дает нам один метод - возможность переводить «себя» в контейнер текста / правил перевода. Таким образом, форме не нужно знать, какой тип элемента управления она обнаружила, только то, что она реализует конкретный интерфейс и знает, что существует метод, который она может вызвать для локализации элемента управления.

person Lasse V. Karlsen    schedule 21.12.2008
comment
Зачем упоминать IoC в самом начале, поскольку это только добавит путаницы. - person Kevin Le - Khnle; 21.12.2008
comment
Согласитесь, я бы сказал, что программирование с использованием интерфейсов - это просто способ сделать IoC более простым и надежным. - person terjetyl; 21.12.2008

Код для интерфейса, а не реализация, НИЧЕГО не имеет отношения к Java или ее конструкции интерфейса.

Эта концепция получила известность в книгах «Паттерны / Банда четырех», но, скорее всего, была известна задолго до этого. Эта концепция определенно существовала задолго до появления Java.

Конструкция интерфейса Java была создана, чтобы помочь в реализации этой идеи (среди прочего), и люди стали слишком сосредоточены на конструкции как на центре смысла, а не на первоначальном замысле. Однако по этой причине у нас есть общедоступные и частные методы и атрибуты в Java, C ++, C # и т. Д.

Это означает просто взаимодействие с объектом или общедоступным интерфейсом системы. Не беспокойтесь и даже не ожидайте, как он будет делать то, что делает внутри. Не беспокойтесь о том, как это реализовано. В объектно-ориентированном коде именно поэтому у нас есть публичные и частные методы / атрибуты. Мы намерены использовать общедоступные методы, потому что частные методы предназначены только для внутреннего использования внутри класса. Они составляют реализацию класса и могут быть изменены по мере необходимости без изменения публичного интерфейса. Предположим, что в отношении функциональности метод класса будет выполнять одну и ту же операцию с тем же ожидаемым результатом каждый раз, когда вы вызываете его с теми же параметрами. Это позволяет автору изменить способ работы класса, его реализацию, не нарушая того, как люди взаимодействуют с ним.

И вы можете программировать интерфейс, а не реализацию, никогда не используя конструкцию интерфейса. Вы можете программировать интерфейс, а не реализацию на C ++, которая не имеет конструкции интерфейса. Вы можете интегрировать две массивные корпоративные системы гораздо более надежно, если они взаимодействуют через общедоступные интерфейсы (контракты), а не вызывают методы для объектов, внутренних по отношению к системам. Ожидается, что интерфейсы всегда будут реагировать одинаково ожидаемым образом при одинаковых входных параметрах; если реализовано в интерфейсе, а не в реализации. Эта концепция работает во многих местах.

Избавьтесь от мысли, что интерфейсы Java имеют какое-то отношение к концепции «программа для интерфейса, а не реализация». Они могут помочь применить концепцию, но это не концепция.

person Bill Rosmus    schedule 14.04.2016
comment
Первое предложение говорит само за себя. Это должен быть принятый ответ. - person madumlao; 23.04.2017

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

// if I want to add search capabilities to my application and support multiple search
// engines such as Google, Yahoo, Live, etc.

interface ISearchProvider
{
    string Search(string keywords);
}

тогда я мог бы создать GoogleSearchProvider, YahooSearchProvider, LiveSearchProvider и т. д.

// if I want to support multiple downloads using different protocols
// HTTP, HTTPS, FTP, FTPS, etc.
interface IUrlDownload
{
    void Download(string url)
}

// how about an image loader for different kinds of images JPG, GIF, PNG, etc.
interface IImageLoader
{
    Bitmap LoadImage(string filename)
}

затем создайте JpegImageLoader, GifImageLoader, PngImageLoader и т. д.

Большинство надстроек и плагинов работают без интерфейсов.

Еще одно популярное использование - шаблон репозитория. Скажем, я хочу загрузить список почтовых индексов из разных источников.

interface IZipCodeRepository
{
    IList<ZipCode> GetZipCodes(string state);
}

тогда я мог бы создать XMLZipCodeRepository, SQLZipCodeRepository, CSVZipCodeRepository и т. д. Для своих веб-приложений я часто создаю XML-репозитории на раннем этапе, чтобы я мог что-то запустить до того, как будет готова база данных SQL. Когда база данных готова, я пишу SQLRepository для замены версии XML. Остальная часть моего кода осталась неизменной, так как она работает исключительно через интерфейсы.

Методы могут принимать такие интерфейсы, как:

PrintZipCodes(IZipCodeRepository zipCodeRepository, string state)
{
    foreach (ZipCode zipCode in zipCodeRepository.GetZipCodes(state))
    {
        Console.WriteLine(zipCode.ToString());
    }
}
person Todd Smith    schedule 21.12.2008

Есть много объяснений, но чтобы сделать это еще проще. Возьмем, к примеру, List. Список можно реализовать как:

  1. Внутренний массив
  2. Связанный список
  3. Другие реализации

Создавая интерфейс, скажите List. Вы кодируете только определение List или то, что List означает на самом деле.

Вы можете использовать любой тип внутренней реализации, скажем, array. Но предположим, что вы хотите изменить реализацию по какой-то причине, например из-за ошибки или производительности. Тогда вам просто нужно изменить объявление List<String> ls = new ArrayList<String>() на List<String> ls = new LinkedList<String>().

Больше нигде в коде вам не придется ничего менять; Потому что все остальное было построено на определении List.

person Jatin    schedule 15.04.2013

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

Я работаю над программным обеспечением на стороне клиента, которое взаимодействует с сервером, на котором запущено медицинское устройство. Мы разрабатываем новую версию этого устройства, в которой есть некоторые новые компоненты, которые заказчик должен время от времени настраивать. Есть два типа новых компонентов, и они разные, но они также очень похожи. По сути, мне пришлось создать две формы конфигурации, два класса списков, по два всего.

Я решил, что было бы лучше создать абстрактный базовый класс для каждого типа элемента управления, который содержал бы почти всю реальную логику, а затем производные типы, чтобы позаботиться о различиях между двумя компонентами. Однако базовые классы не смогли бы выполнять операции с этими компонентами, если бы мне все время приходилось беспокоиться о типах (ну, они могли бы, но в каждом методе был бы оператор «if» или переключатель) .

Я определил простой интерфейс для этих компонентов, и все базовые классы взаимодействуют с этим интерфейсом. Теперь, когда я что-то меняю, это практически везде «просто работает», и у меня нет дублирования кода.

person Ed S.    schedule 21.12.2008

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

person Kevin Le - Khnle    schedule 21.12.2008
comment
Это не только полезно в случае появления более качественного драйвера, но и позволяет полностью изменить поставщиков баз данных. - person Ken Liu; 21.12.2008
comment
JDBC настолько плох, что его нужно заменить. Найдите другой пример. - person Joshua; 05.01.2011
comment
JDBC - это плохо, но не по какой-либо причине, связанной с интерфейсом, реализацией или уровнями абстракции. Итак, чтобы проиллюстрировать рассматриваемую концепцию, она просто идеальна. - person Erwin Smout; 12.03.2019

Программирование через интерфейсы - это круто, оно способствует слабой связи. Как упоминалось в @lassevk, Inversion of Control отлично подходит для этого.

Кроме того, ознакомьтесь с принципалами SOLID. вот серия видео

Он проходит через жестко запрограммированный (пример с сильной связью), затем просматривает интерфейсы, наконец, переходит к инструменту IoC / DI (NInject).

person dbones    schedule 21.12.2008

Я поздно задал этот вопрос, но хочу упомянуть здесь, что строка «Программа для интерфейса, а не реализация» хорошо обсуждалась в книге «Шаблоны проектирования GoF (Gang of Four)».

В нем говорится, на стр. 18:

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

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

и выше это началось с:

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

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

Другими словами, не пишите свои классы так, чтобы у них был метод quack() для уток, а затем метод bark() для собак, потому что они слишком специфичны для конкретной реализации класса (или подкласса). Вместо этого напишите метод, используя имена, которые являются достаточно общими для использования в базовом классе, например giveSound() или move(), чтобы их можно было использовать для уток, собак или даже автомобилей, и тогда клиент ваших классов может просто сказать .giveSound() вместо того, чтобы думать о том, использовать ли quack() или bark() или даже определить тип, прежде чем выдать правильное сообщение, которое будет отправлено объекту.

person nonopolarity    schedule 01.01.2016

В дополнение к уже выбранному ответу (и различным информационным сообщениям здесь) я настоятельно рекомендую взять копию Head First Паттерны дизайна. Его очень легко читать, и он напрямую ответит на ваш вопрос, объяснит, почему он важен, и покажет вам множество шаблонов программирования, которые вы можете использовать для использования этого принципа (и других).

person whaley    schedule 08.01.2009

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

person e11s    schedule 21.12.2008

Программирование интерфейсов может быть выгодным, даже если мы не зависим от абстракций.

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

  1. не позволяет нам делать вещи, не соответствующие контексту, и
  2. позволяет нам безопасно изменять реализацию в будущем.

Например, рассмотрим класс Person, реализующий интерфейс Friend и Employee.

class Person implements AbstractEmployee, AbstractFriend {
}

В контексте дня рождения человека мы программируем интерфейс Friend, чтобы предотвратить обращение с человеком как с Employee.

function party() {
    const friend: Friend = new Person("Kathryn");
    friend.HaveFun();
}

В контексте работы человека мы программируем Employee интерфейс, чтобы не стирать границы рабочего места.

function workplace() {
    const employee: Employee = new Person("Kathryn");
    employee.DoWork();
}

Большой. Мы вели себя надлежащим образом в разных контекстах, и наше программное обеспечение работает хорошо.

В далеком будущем, если наш бизнес перейдет на работу с собаками, мы сможем довольно легко изменить программное обеспечение. Сначала мы создаем класс Dog, который реализует как Friend, так и Employee. Затем мы безопасно меняем new Person() на new Dog(). Даже если обе функции содержат тысячи строк кода, это простое редактирование будет работать, потому что мы знаем, что верно следующее:

  1. Функция party использует только Friend подмножество Person.
  2. Функция workplace использует только Employee подмножество Person.
  3. Класс Dog реализует интерфейсы Friend и Employee.

С другой стороны, если бы party или workplace были запрограммированы против Person, был бы риск того, что у обоих будет Person специфический код. Переход с Person на Dog потребует от нас прочесывания кода, чтобы удалить любой Person специфический код, который Dog не поддерживает.

Мораль: программирование интерфейсов помогает нашему коду вести себя надлежащим образом и быть готовым к изменениям. Он также подготавливает наш код к тому, чтобы он зависел от абстракций, что дает еще больше преимуществ.

person Shaun Luttin    schedule 03.07.2017
comment
Предполагая, что у вас нет чрезмерно широких интерфейсов. - person Casey; 18.07.2017

Если я пишу новый класс Swimmer для добавления функций swim() и мне нужно использовать объект класса, скажите Dog, и этот Dog класс реализует интерфейс Animal, который объявляет swim().

В верхней части иерархии (Animal) она очень абстрактна, в то время как внизу (Dog) она очень конкретна. Я думаю о «программировании для интерфейсов» так, что, когда я пишу класс Swimmer, я хочу написать свой код для интерфейса, который находится так же высоко в этой иерархии, которая в данном случае является объектом Animal. Интерфейс свободен от деталей реализации и, таким образом, делает ваш код слабосвязанным.

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

person Abhishek Shrivastava    schedule 28.04.2010

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

person Richard    schedule 08.01.2009

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

Например, у меня может быть интерфейс движения. Метод, который заставляет что-то «двигаться» и любой объект (Person, Car, Cat), реализующий интерфейс движения, может быть передан и ему будет приказано двигаться. Без метода все знают, что это за класс.

person Damien    schedule 21.12.2008

Представьте, что у вас есть продукт под названием «Зебра», который можно расширять с помощью плагинов. Он находит плагины путем поиска DLL в каком-либо каталоге. Он загружает все эти библиотеки DLL и использует отражение для поиска любых классов, реализующих IZebraPlugin, а затем вызывает методы этого интерфейса для связи с подключаемыми модулями.

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

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

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

person Daniel Earwicker    schedule 21.12.2008

Объяснение C ++.

Думайте об интерфейсе как о публичных методах вашего класса.

Затем вы можете создать шаблон, который «зависит» от этих общедоступных методов, чтобы выполнять свою собственную функцию (он выполняет вызовы функций, определенные в общедоступном интерфейсе классов). Допустим, этот шаблон является контейнером, как класс Vector, а интерфейс, от которого он зависит, является алгоритмом поиска.

Любой класс алгоритма, который определяет функции / интерфейс, которые вызывает Vector, будет удовлетворять «контракту» (как кто-то объяснил в исходном ответе). Алгоритмы даже не обязательно должны принадлежать к одному и тому же базовому классу; единственное требование - чтобы функции / методы, от которых зависит вектор (интерфейс), были определены в вашем алгоритме.

Смысл всего этого в том, что вы можете предоставить любой другой алгоритм / класс поиска, лишь бы он предоставлял интерфейс, от которого зависит Vector (поиск пузырьков, последовательный поиск, быстрый поиск).

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

Это экономит время (принцип ООП «повторное использование кода»), поскольку вы можете писать алгоритм один раз, а не снова и снова, снова и снова, специфичный для каждого нового объекта, который вы создаете, не усложняя проблему чрезмерно разросшимся деревом наследования.

Что касается «упущения» того, как все работает; большое время (по крайней мере, в C ++), поскольку именно так работает большая часть инфраструктуры стандартной библиотеки TEMPLATE.

Конечно, при использовании наследования и абстрактных классов методология программирования интерфейса меняется; но принцип тот же, ваши общедоступные функции / методы - это интерфейс ваших классов.

Это огромная тема и один из краеугольных принципов паттернов дизайна.

person Trae Barlow    schedule 18.12.2012

В Java все эти конкретные классы реализуют интерфейс CharSequence:

CharBuffer, String, StringBuffer, StringBuilder

Эти конкретные классы не имеют общего родительского класса, кроме Object, поэтому нет ничего, что их связывает, кроме того факта, что каждый из них имеет какое-то отношение к массивам символов, представляющих их или манипулирующих ими. Например, символы String не могут быть изменены после создания экземпляра объекта String, тогда как символы StringBuffer или StringBuilder можно редактировать.

Тем не менее, каждый из этих классов может соответствующим образом реализовать методы интерфейса CharSequence:

char charAt(int index)
int length()
CharSequence subSequence(int start, int end)
String toString()

В некоторых случаях классы библиотеки классов Java, которые раньше принимали String, были изменены, чтобы теперь принимать интерфейс CharSequence. Поэтому, если у вас есть экземпляр StringBuilder, вместо извлечения объекта String (что означает создание экземпляра нового экземпляра объекта) он может вместо этого просто передать сам StringBuilder, поскольку он реализует интерфейс CharSequence.

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

BufferedWriter, CharArrayWriter, CharBuffer, FileWriter, FilterWriter, LogStream, OutputStreamWriter, PipedWriter, PrintStream, PrintWriter, StringBuffer, StringBuilder, StringWriter, Writer

person RogerV    schedule 21.12.2008
comment
Жаль, что интерфейсы типа CharSequence такие анемичные. Я бы хотел, чтобы Java и .NET позволяли интерфейсам иметь реализацию по умолчанию, чтобы люди не сокращали интерфейсы исключительно с целью минимизации шаблонного кода. При наличии любой законной CharSequence реализации можно было бы эмулировать большинство функций String, используя только четыре вышеуказанных метода, но многие реализации могли бы выполнять эти функции гораздо более эффективно другими способами. К сожалению, даже если конкретная реализация CharSequence содержит все в одном char[] и может выполнять множество ... - person supercat; 18.10.2014
comment
... операции типа indexOf быстро, нет никакого способа, чтобы вызывающий, не знакомый с конкретной реализацией CharSequence, мог попросить его об этом, вместо того, чтобы использовать charAt для проверки каждого отдельного символа. - person supercat; 18.10.2014

Краткая история: почтальона просят пойти домой после дома и получить обложки (письма, документы, чеки, подарочные карты, заявление, любовное письмо) с написанным на нем адресом для доставки.

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

Так что лучше оберните его крышкой (в нашей истории это интерфейс), тогда он отлично справится со своей работой.

Теперь работа почтальона - принимать и доставлять только обложки (его бы не беспокоило, что внутри обложки).

Создайте тип interface не фактического типа, а реализуйте его с фактическим типом.

Создание интерфейса означает, что ваши компоненты легко вписываются в остальной код

Приведу вам пример.

у вас есть интерфейс AirPlane, как показано ниже.

interface Airplane{
    parkPlane();
    servicePlane();
}

Предположим, у вас есть методы в вашем классе контроллеров самолетов, например

parkPlane(Airplane plane)

а также

servicePlane(Airplane plane)

реализовано в вашей программе. Это не будет BREAK вашего кода. Я имею в виду, что его не нужно менять, пока он принимает аргументы как AirPlane.

Потому что он будет принимать любой самолет, независимо от его фактического типа, flyer, highflyr, fighter и т. Д.

Также в коллекции:

List<Airplane> plane; // Заберут все ваши самолеты.

Следующий пример прояснит ваше понимание.


У вас есть истребитель, который это реализует, так что

public class Fighter implements Airplane {

    public void  parkPlane(){
        // Specific implementations for fighter plane to park
    }
    public void  servicePlane(){
        // Specific implementatoins for fighter plane to service.
    }
}

То же самое для HighFlyer и других классов:

public class HighFlyer implements Airplane {

    public void  parkPlane(){
        // Specific implementations for HighFlyer plane to park
    }

    public void  servicePlane(){
        // specific implementatoins for HighFlyer plane to service.
    }
}

Теперь подумайте, что ваши классы контроллера используют AirPlane несколько раз,

Предположим, что ваш класс контроллера - ControlPlane, как показано ниже,

public Class ControlPlane{ 
 AirPlane plane;
 // so much method with AirPlane reference are used here...
}

Здесь приходит волшебство, поскольку вы можете создавать сколько угодно новых экземпляров типа AirPlane, не изменяя при этом код класса ControlPlane.

Вы можете добавить экземпляр ...

JumboJetPlane // implementing AirPlane interface.
AirBus        // implementing AirPlane interface.

Вы также можете удалить экземпляры ранее созданных типов.

person Sanjay Rabari    schedule 08.08.2014

Интерфейс похож на контракт, где вы хотите, чтобы ваш класс реализации реализовал методы, написанные в контракте (интерфейсе). Поскольку Java не обеспечивает множественного наследования, «программирование с интерфейсом» - хороший способ добиться множественного наследования.

Если у вас есть класс A, который уже расширяет какой-то другой класс B, но вы хотите, чтобы этот класс A также следовал определенным рекомендациям или реализовывал определенный контракт, то вы можете сделать это с помощью стратегии «программирование для интерфейса».

person Shivam Sugandhi    schedule 27.05.2016

Q: - ... Можете ли вы использовать какой-либо класс, реализующий интерфейс?
A: - Да.

Q: - ... Когда вам нужно это сделать?
A: - Каждый раз, когда вам нужен класс (ы), реализующий интерфейс (ы).

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

  • Почему?
  • Поскольку интерфейс имеет только прототипы методов, а не определения (только имена функций, а не их логику)

AnIntf anInst = new Aclass();
// мы могли бы сделать это только если Aclass реализует AnIntf.
// anInst будет иметь ссылку на Aclass.


Примечание. Теперь мы могли понять, что произошло бы, если бы Bclass и Cclass реализовали один и тот же Dintf.

Dintf bInst = new Bclass();  
// now we could call all Dintf functions implemented (defined) in Bclass.

Dintf cInst = new Cclass();  
// now we could call all Dintf functions implemented (defined) in Cclass.

Что у нас есть: одинаковые прототипы интерфейса (имена функций в интерфейсе) и разные реализации.

Библиография: Прототипы - википедия

person Community    schedule 09.03.2014

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

IInterface classRef = new ObjectWhatever()

Вы могли бы использовать любой класс, реализующий IInterface? Когда вам нужно это сделать?

Взгляните на этот вопрос SE для хорошего примера.

Почему интерфейс для класса Java быть предпочтительнее?

влияет ли использование интерфейса на производительность?

если да, то сколько?

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

как этого избежать без необходимости поддерживать два бита кода?

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

Один хороший вариант использования: реализация шаблона стратегии:

Пример шаблона стратегии в реальном мире

person Ravindra babu    schedule 27.12.2016

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

Модульное тестирование

Последние два года я написал хобби-проект и не писал для него модульных тестов. Написав около 50 тысяч строк, я понял, что действительно необходимо писать модульные тесты. Я не использовал интерфейсы (или очень экономно) ... и когда я сделал свой первый модульный тест, я обнаружил, что это сложно. Почему?

Потому что мне пришлось создать множество экземпляров класса, используемых для ввода в качестве переменных и / или параметров класса. Таким образом, тесты больше похожи на интеграционные тесты (необходимость составлять полную «структуру» классов, поскольку все было связано вместе).

Боязнь интерфейсов. Итак, я решил использовать интерфейсы. Я опасался, что мне придется реализовывать всю функциональность везде (во всех используемых классах) несколько раз. В некотором роде это правда, однако, используя наследование, его можно значительно уменьшить.

Комбинация интерфейсов и наследования. Я обнаружил, что комбинация очень удобна для использования. Приведу очень простой пример.

public interface IPricable
{
    int Price { get; }
}

public interface ICar : IPricable

public abstract class Article
{
    public int Price { get { return ... } }
}

public class Car : Article, ICar
{
    // Price does not need to be defined here
}

Таким образом, копирование кода не требуется, но при этом можно использовать автомобиль в качестве интерфейса (ICar).

person Michel Keijzers    schedule 18.12.2014

Начнем с некоторых определений:

Интерфейс n.. Набор всех сигнатур, определенных операциями объекта, называется интерфейсом к объекту.

Тип n. Определенный интерфейс.

Простым примером интерфейса, как определено выше, могут быть все методы объекта PDO, такие как query(), commit(), close() и т. Д., В целом, а не по отдельности. Эти методы, то есть его интерфейс, определяют полный набор сообщений, запросов, которые могут быть отправлены объекту.

Тип, как определено выше, - это особый интерфейс. Я буду использовать интерфейс вымышленной формы, чтобы продемонстрировать: draw(), getArea(), getPerimeter() и т. Д.

Если объект относится к типу «База данных», мы имеем в виду, что он принимает сообщения / запросы интерфейса базы данных, query(), commit() и т. Д. Объекты могут быть разных типов. У вас может быть объект базы данных типа shape, если он реализует свой интерфейс, и в этом случае это будет подтип.

Многие объекты могут иметь множество различных интерфейсов / типов и реализовывать этот интерфейс по-разному. Это позволяет нам заменять объекты, позволяя выбирать, какой из них использовать. Также известен как полиморфизм.

Клиент будет знать только об интерфейсе, но не о реализации.

Таким образом, в сущности, программирование интерфейса потребовало бы создания некоторого типа абстрактного класса, такого как Shape, с указанным только интерфейсом, т.е. draw(), getCoordinates(), getArea() и т. Д. А затем различные конкретные классы реализуют эти интерфейсы, такие как класс Circle, класс Square, Класс треугольника. Следовательно, программа для интерфейса, а не реализация.

person Robert Rocha    schedule 05.08.2015

«Программа для интерфейса» означает, что жесткий код не предоставляется должным образом, то есть ваш код должен быть расширен без нарушения предыдущей функциональности. Просто расширения, а не редактирование предыдущего кода.

person ndoty    schedule 30.07.2018

программа к интерфейсу - это термин из книги GOF. Я бы не сказал прямо, что это связано с java-интерфейсом, скорее с реальными интерфейсами. для достижения чистого разделения уровней вам нужно создать некоторое разделение между системами, например: допустим, у вас есть конкретная база данных, которую вы хотите использовать, вы никогда не будете «программировать для базы данных», вместо этого вы бы «запрограммировали для интерфейса хранилища». Точно так же вы никогда не будете «программировать для веб-службы», а скорее будете программировать для «клиентского интерфейса». это так, чтобы вы могли легко поменять местами.

Я считаю, что эти правила мне помогают:

1. мы используем интерфейс java, когда у нас есть несколько типов объекта. если у меня есть только один объект, я не вижу в этом смысла. если есть хотя бы две конкретные реализации какой-то идеи, то я бы использовал интерфейс java.

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

обратите внимание на два способа их использования. надеюсь это поможет.

person j2emanue    schedule 02.02.2020

Я твердо верю, что сложные вопросы следует объяснять простыми реальными ответами. А в сфере разработки программного обеспечения это очень важно.

Посмотрите на любую дверь в вашем доме, школе, церкви ... любом здании.

Представьте, что у некоторых дверей есть опасности справа внизу (поэтому вам нужно наклониться, чтобы взаимодействовать с дверью, которая открывает или закрывает ее),

Или другие попали в верхний левый угол (так, некоторые гномы, люди с ограниченными возможностями или Кевин Харт не сочтут такие двери очень забавными и удобными).

Итак, дизайн - ключевое слово, создавайте программы, чтобы другие люди могли разрабатывать / использовать.

Interfaces упрощает задачу другим младшим и старшим разработчикам в колоссальных проектах [1], чтобы все знали, что они делают с небольшой помощью других, чтобы вы могли работать максимально гладко (в теории).


[1]: Как? Раскрывая форму ценности. Таким образом, вам не нужна документация, потому что сам код не требует пояснений (Замечательно).


Этот ответ не предназначался для конкретного языка, а не для концепции (в конце концов, люди создают инструменты, написав код).

person Yoarthur    schedule 26.03.2019

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

//This interface is very flexible and abstract
    addPassenger(Plane seat, Ticket ticket); 

//Boeing is implementation of Plane
    addPassenger(Boeing747 seat, EconomyTicket ticket); 
    addPassenger(Cessna, BusinessClass ticket);


    addPassenger(J15, E87687); 
person Wil    schedule 19.12.2014