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

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

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

Это просто так, если вам нужно сделать:

IInterface classRef = new ObjectWhatever() 

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

Извините, если я полностью пропустил точку.

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

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

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

  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(); } } 

Теперь у нас есть два classа, каждый из которых может раздражать по-своему. И им не нужно выводить из одного базового classа и IPest общими присущими характеристиками – им просто нужно удовлетворить контракт 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 который является вредителем, нам все равно, что это такое, и они могут не имеют ничего общего с другими.

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

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

 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 , не заставят вас изменить код вызова.

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

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

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

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

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

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

Вы должны посмотреть на инверсию управления:

  • Мартин Фаулер: инверсия контрольных контейнеров и модель впрыска зависимостей
  • Википедия: инверсия контроля

В таком случае вы не будете писать это:

 IInterface classRef = new ObjectWhatever(); 

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

 IInterface classRef = container.Resolve(); 

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

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

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

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

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

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

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

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

Позвольте мне привести конкретный пример.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 // 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 и т. д.

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

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

 interface IZipCodeRepository { IList GetZipCodes(string state); } 

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

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

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

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

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

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

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

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

Программирование на интерфейсы является удивительным, оно способствует свободному соединению. Как отметил @lassevk, «Инверсия управления» – это большое использование.

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

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

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

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

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

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

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

Нет, где еще в коде, вам придется что-то изменить; Потому что все остальное было построено на определении List .

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

На стр. 18:

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

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

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

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

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

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

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

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

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

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

Представьте, что у вас есть продукт под названием «Zebra», который может быть дополнен плагинами. Он находит плагины, ища библиотеки DLL в некоторых каталогах. It loads all those DLLs and uses reflection to find any classes that implement IZebraPlugin , and then calls the methods of that interface to communicate with the plugins.

This makes it completely independent of any specific plugin class – it doesn’t care what the classes are. It only cares that they fulfill the interface specification.

Interfaces are a way of defining points of extensibility like this. Code that talks to an interface is more loosely coupled – in fact it is not coupled at all to any other specific code. It can inter-operate with plugins written years later by people who have never met the original developer.

You could instead use a base class with virtual functions – all plugins would be derived from the base class. But this is much more limiting because a class can only have one base class, whereas it can implement any number of interfaces.

C++ explanation.

Think of an interface as your classes public methods.

You then could create a template that ‘depends’ on these public methods in order to carry out it’s own function (it makes function calls defined in the classes public interface). Lets say this template is a container, like a Vector class, and the interface it depends on is a search algorithm.

Any algorithm class that defines the functions/interface Vector makes calls to will satisfy the ‘contract’ (as someone explained in the original reply). The algorithms don’t even need to be of the same base class; the only requirement is that the functions/methods that the Vector depends on (interface) is defined in your algorithm.

The point of all of this is that you could supply any different search algorithm/class just as long as it supplied the interface that Vector depends on (bubble search, sequential search, quick search).

You might also want to design other containers (lists, queues) that would harness the same search algorithm as Vector by having them fulfill the interface/contract that your search algorithms depends on.

This saves time (OOP principle ‘code reuse’) as you are able to write an algorithm once instead of again and again and again specific to every new object you create without over-complicating the issue with an overgrown inheritance tree.

As for ‘missing out’ on how things operate; big-time (at least in C++), as this is how most of the Standard TEMPLATE Library’s framework operates.

Of course when using inheritance and abstract classes the methodology of programming to an interface changes; but the principle is the same, your public functions/methods are your classes interface.

This is a huge topic and one of the the cornerstone principles of Design Patterns.

In Java these concrete classes all implement the CharSequence interface:

CharBuffer, String, StringBuffer, StringBuilder

These concrete classes do not have a common parent class other than Object, so there is nothing that relates them, other than the fact they each have something to do with arrays of characters, representing such, or manipulating such. For instance, the characters of String cannot be changed once a String object is instantiated, whereas the characters of StringBuffer or StringBuilder can be edited.

Yet each one of these classes is capable of suitably implementing the CharSequence interface methods:

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

In some cases Java class library classes that used to accept String have been revised to now accept the CharSequence interface. So if you have an instance of StringBuilder, instead of extracting a String object (which means instantiating a new object instance), can instead just pass the StringBuilder itself as it implements the CharSequence interface.

The Appendable interface that some classes implement has much the same kind of benefit for any situation where characters can be appended to an instance of the underlying concrete class object instance. All of these concrete classes implement the Appendable interface:

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

In simple terms… If I’m writing a new class Swimmer to add the functionality swim() and need to use an object of class say Dog, and this Dog class implements interface Animal which declares swim()[To better understand…you may draw a diagram as to what I am talking about]. At the top of the hierarchy(Animal) it’s very abstract while at the bottom (Dog) it’s very concrete. The way I think about “programming to interfaces” is that, as I write Swimmer class, I want to write my code against the interface that’s as far up that hierarchy which in this case is Animal object. An interface is free from implementation details and thus makes your code loosely-coupled. The implementation details can be changed with time, however it would not affect the remaining code since all you are interacting is with the interface and not the implementation. You don’t care what the implementation is like…all you know is that there will be a class that would implement the interface.

short story:Postman is asked to go home by home and receive the covers contains (letters,documents,cheques,giftcard,application,loveletter) with address written on it to deliver.

Suppose there is no cover and ask post man to go home by home and receive all the things and deliver to other person the postman can get confuse,

so better wrap it with cover(in our story it is interface) then he will do his job fine.

Now postman job is to receive and deliver the covers only..(he dont bothered what is inside in the cover).

Create type of interface not actual type, but implement with actual type.

Create to interface means your components get Fits into the rest of code easily

I give you example.

you have AirPlane interface as below.

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

Suppose you have methods in your Controller class of Planes like

 parkPlane(Airplane plane) 

а также

 servicePlane(Airplane plane) 

implemented in your program. It will not BREAK your code. I mean, it need not to change as long as it accepts arguments as AirPlane .

Because it will accept any Airplane despite of actual type, flyer , highflyr , fighter , etc.

Also, in a collection:

List plane; // Will take all your planes.

The following example will clear your understanding.


You have a fighter plane that implements it, so

 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. } } 

The same thing for HighFlyer and other clasess:

 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. } } 

Now think your controller classes using AirPlane several times,

Suppose your Controller class is ControlPlane like below,

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

here magic comes as

you may make your new AirPlane type instances as many as you want and you are not changing

code of ControlPlane class.

you can add instance..

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

you may remove instances.. of previously created types too.

Q: – … “You could use any class that implements interface?”
A: – Yes.

Q: -… “When would you need to do that?”
A: – Each time you need a class(es) that implements interface(s).

Note: we couldn’t instantiate an interface not implemented by a classTrue.

  • why?
  • because interface has only methods prototypes, not definitions (just functions names, not their logic)

AnIntf anInst = new Aclass();
// we could do this only if Aclass implements AnIntf.
// anInst will have Aclass reference.


Заметка:
Now we could understand what happend if Bclass and Cclass implements same 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. 

What we have:
same interface prototypes (functions names in interface), and call different implementations.

Bibliography:
Prototypes – wikipedia

Interface is like contract where you want your implementation class to implement methods written in contract(Interface).Since java does not provide multiple inheritance,programming to interface is a good way to achieve purpose of multiple inheritance.If you have a class A that is already extending some other class B but you want that class A should also follow certain guidelines or implement certain contract then you can do so by programming to interface strategy.

It can be advantageous to program to interfaces, even when we are not depending on abstractions.

Programming to interfaces forces us to use a contextually appropriate subset of an object. That helps because it:

  1. prevents us from doing contextually inappropriate things, and
  2. lets us safely change the implementation in the future.

For example, consider a Person class that implements the Friend and the Employee interface.

 class Person implements AbstractEmployee, AbstractFriend { } 

In the context of the person’s birthday, we program to the Friend interface, to prevent treating the person like an Employee .

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

In the context of the person’s work, we program to the Employee interface, to prevent blurring workplace boundaries.

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

Отлично. We have behaved appropriately in different contexts, and our software is working well.

Far into the future, if our business changes to work with dogs, we can change the software fairly easily. First, we create Dog class that implements both Friend and Employee . Then, we safely change new Person() to new Dog() . Even if both functions have thousands of lines of code, that simple edit will work because we know the following are true:

  1. Function party uses only the Friend subset of Person .
  2. Function workplace uses only the Employee subset of Person .
  3. Class Dog implements both the Friend and Employee interfaces.

On the other hand, if either party or workplace were to have programmed against Person , there would be a risk of both having Person -specific code. Changing from Person to Dog would require us to comb through the code to extirpate any Person -specific code that Dog does not support.

The moral : programming to interfaces helps our code to behave appropriately and to be ready for change. It also prepares our code to depend on abstractions, which brings even more advantages.

Also I see a lot of good and explanatory answers here, so I want to give my point of view here, including some extra information what I noticed when using this method.

Unit testing

For the last two years, I have written a hobby project and I did not write unit tests for it. After writing about 50K lines I found out it would be really necessary to write unit tests. I did not use interfaces (or very sparingly) … and when I made my first unit test, I found out it was complicated. Зачем?

Because I had to make a lot of class instances, used for input as class variables and/or parameters. So the tests look more like integration tests (having to make a complete ‘framework’ of classes since all was tied together).

Fear of interfaces So I decided to use interfaces. My fear was that I had to implement all functionality everywhere (in all used classes) multiple times. In some way this is true, however, by using inheritance it can be reduced a lot.

Combination of interfaces and inheritance I found out the combination is very good to be used. I give a very simple example.

 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 } 

This way copying code is not necessary, while still having the benefit of using a car as interface (ICar).

Let’s start out with some definitions first:

Interface n. The set of all signatures defined by an object’s operations is called the interface to the object

Type n. A particular interface

A simple example of an interface as defined above would be all the PDO object methods such as query() , commit() , close() etc., as a whole, not separately. These methods, ie its interface define the complete set of messages, requests that can be sent to the object.

A type as defined above is a particular interface. I will use the made-up shape interface to demonstrate: draw() , getArea() , getPerimeter() etc..

If an object is of the Database type we mean that it accepts messages/requests of the database interface, query() , commit() etc.. Objects can be of many types. You can have a database object be of the shape type as long as it implements its interface, in which case this would be sub-typing .

Many objects can be of many different interfaces/types and implement that interface differently. This allows us to substitute objects, letting us choose which one to use. Also known as polymorphism.

The client will only be aware of the interface and not the implementation.

So in essence programming to an interface would involve making some type of abstract class such as Shape with the interface only specified ie draw() , getCoordinates() , getArea() etc.. And then have different concrete classes implement those interfaces such as a Circle class, Square class, Triangle class. Hence program to an interface not an implementation.

Program to an interface allows to change implementation of contract defined by interface seamlessly. It allows loose coupling between contract and specific implementations.

IInterface classRef = new ObjectWhatever()

You could use any class that implements IInterface? When would you need to do that?

Have a look at this SE question for good example.

Why should the interface for a Java class be preferred?

does using an Interface hit performance?

if so how much?

Да. It will have slight performance overhead in sub-seconds. But if your application has requirement to change the implementation of interface dynamically, don’t worry about performance impact.

how can you avoid it without having to maintain two bits of code?

Don’t try to avoid multiple implementations of interface if your application need them. In absence of tight coupling of interface with one specific implementation, you may have to deploy the patch to change one implementation to other implementation.

One good use case: Implementation of Strategy pattern:

Real World Example of the Strategy Pattern

I don’t retain interface s are the most important thing in a language: it’s more commonly used the class inheriting. But anyway they are important!
For example (this is Java code, but it can simply adapted to C# or many other languages):

 interface Convertable { T convert(); } public class NumerableText implements Convertable { private String text = ""; public NumerableText() { } public NumerableText(String text) { this.text = text; } public String getText() { return this.text; } public void setText(String text) { this.text = text; } public Integer convert() { return this.text.hashCode(); } } public class NumerableTextArray implements Convertable { private String[] textArray = ""; public NumerableTextArray() { } public NumerableTextArray(String[] textArray) { this.textArray = textArray; } public String[] getTextArray() { return this.textArray; } public void setTextArray(String[] text) { this.textArray = textArray; } public Integer convert() { Integer value = 0; for (String text : textArray) value += text.hashCode(); return value; } } public class Foo { public static void main() { Convertable num1 = new NumerableText("hello"); Convertable num2 = new NumerableTextArray(new String[] { "test n°1", "test n°2" }); System.out.println(String.valueOf(num1.convert())); System.out.println(String.valueOf(num2.convert())); //Here are you two numbers generated from two classes of different type, but both with the method convert(), which allows you to get that number. } } 

Program to interface means dont provide hard codes right the way, means your codes should be extended without break the previous functionality….. just extensions not editing the prev codes

  • Что такое функция обратного вызова?
  • Вычисление двумерного векторного изображения
  • Что такое бокс и распаковка и какие компромиссы?
  • Наиболее эффективная реализация classа большого числа
  • Могу ли я прочитать hash-часть URL-адреса моего серверного приложения (PHP, Ruby, Python и т. Д.)?
  • Interesting Posts
    Давайте будем гением компьютера.