Чем полезны интерфейсы?


158

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

C # - отличный язык, но иногда он дает вам ощущение, что сначала Microsoft создает проблему (не разрешая множественное наследование), а затем предлагает решение, которое довольно утомительно.

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


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

37
Забудьте C #, забудьте Java, забудьте язык. Это просто мышление с точки зрения ОО. Я бы посоветовал вам взять некоторые материалы для чтения у таких людей, как Роберт С. Мартин, Мартин Фаулер, Майкл Фезерс, «Банда четырех» и т. Д., Так как это поможет расширить ваше мышление.
Энтони Пеграм

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

37
Тебе нужно многому научиться, друг.
ChaosPandion

60
@ChaosPandion у нас у всех есть
чему

Ответы:


151

Они существуют только для того, чтобы убедиться, что указанные функции (в интерфейсе) реализованы в наследующем классе.

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

Тем не менее, интерфейсы являются довольно слабым способом представления договорных обязательств. Если вы хотите более сильный и гибкий способ представления договорных обязательств, обратите внимание на функцию Code Contracts, которая поставлялась с последней версией Visual Studio.

C # - отличный язык, но иногда возникает ощущение, что сначала Microsoft создает проблему (не допускает множественное наследование), а затем предлагает решение, которое довольно утомительно.

Ну, я рад, что тебе нравится.

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


Я просто читал: «Microsoft создает проблему, не допуская множественного наследования», и я подумал, что Эрику Липперту будет что сказать по этому поводу.
конфигуратор

Более уместно ответить на этот вопрос: Эрик, ты отсылаешь спрашивающего к Кодовым контрактам, но они ужасно неполны; все, кроме самых основных контрактов, не может применяться статической проверкой. Я пытался использовать Code Contract на небольшом проекте; Я добавил сотни строк для каждого метода, указав все, что мог о вводе и выводе, и все же мне пришлось добавить так много Assumeвызовов для случаев, таких как элементы массива или перечисления. После добавления всего и просмотра статически проверенного беспорядка, который я имел, я вернулся к управлению исходным кодом, потому что это снизило качество моего проекта.
конфигуратор

17
@configurator: они неполные, потому что они не могут быть полными; статическая верификация программы с произвольными контрактами эквивалентна решению проблемы остановки. (Например, вы можете написать контракт кода, который говорит, что аргументы метода должны быть контрпримером к последней теореме Ферма; но статический верификатор не сможет проверить, что таких аргументов нет.) Вы использовать его разумно, если вы ожидаете, что статический верификатор завершит свою работу до тепловой смерти вселенной. (Если ваша жалоба состоит в том, что BCL недостаточно аннотирован: я согласен.)
Эрик Липперт,

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

9
+1 за «Ну, я рад, что тебе нравится». И все остальное тоже.
Роберт С.

235

введите описание изображения здесь

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

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


4
Нижний левый объект не выглядит так, как будто он реализует IPowerPlug =)
Стивен Стрига,

100
Блин, но нам придется использовать шаблон адаптера, чтобы использовать IPowerPlug в разных странах!
Стивен Джеурис

Установка устройства для обхода интерфейса с помощью Jerry небезопасна (но некоторые люди по-прежнему делают это часто, ссылаясь на производительность в качестве непроверенного оправдания), и может привести к пожару.
ЮнгДжон

4
Этот ответ просто потрясающий ...
Марио Гарсия

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

145

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

Смысл интерфейсов не в том, чтобы помочь вам вспомнить, какой метод реализовать, он здесь для определения контракта . В примере foreach P.Brian.Mackey (который оказывается неправильным , но нам все равно), IEnumerable определяет контракт между foreach и любой перечисляемой вещью. В нем говорится: «Кем бы вы ни были, пока вы придерживаетесь контракта (реализуйте IEnumerable), я обещаю вам, что буду повторять все ваши элементы». И это здорово (для не динамического языка).

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



Мне не нравится использовать термин "типизирование утки", потому что это означает разные вещи для разных людей. Мы используем сопоставление с образцом для цикла «foreach», потому что когда он был разработан, IEnumerable <T> был недоступен. Мы используем сопоставление с образцом для LINQ, потому что система типов C # слишком слаба, чтобы захватить «нужный нам образец монады»; вам нужно что-то вроде системы типов Haskell.
Эрик Липперт

@Eric: разве «сопоставление с образцом» не имеет той же проблемы? Когда я слышу это, я думаю, F # / Scala / Haskell. Но я предполагаю, что это более широкая идея, чем печатание на утке.
Даниил

@ Даниель: Да, я полагаю, это так. Это шесть из полутора десятков других, я думаю!
Эрик Липперт

36

Интерфейсы - лучший способ поддерживать хорошо отделенные конструкции.

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

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

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

С другой стороны, WPF и Silverlight вообще не играют с интерфейсами, когда дело доходит до связывания. Это довольно неприятная морщина.


2
слышу, слышу! Интерфейсы были изобретены для решения других проблем, таких как полиморфизм. Тем не менее, для меня они вступают в свои права при реализации модели внедрения зависимостей.
Энди

29

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

Как часто вы используете их и что заставляет вас делать это?

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

Нужны разные алгоритмы для выполнения операций над одними и теми же данными? Используйте интерфейс ( см. Шаблон стратегии )!

Хотите использовать разные реализации списка? Код против интерфейса и вызывающей стороны не нужно беспокоиться о реализации!

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


1
Никогда не слышал о полиморфии, вы имеете в виду полиморфизм?
Стивен Джеурис

1
это сказало, что если бы Microsoft разрешила множественное наследование во-первых, не было бы никакой причины для существования интерфейсов
Pankaj Upadhyay

10
@Pankaj Upadhyay: множественное наследование и интерфейсы - это две разные пары обуви. Что делать, если вам нужен интерфейс двух не связанных классов с различным поведением? Вы не можете решить это множественным наследованием. В любом случае, вы должны реализовать это отдельно. И тогда вам нужно что-то, чтобы описать интерфейс, чтобы обеспечить полиморфное поведение. Множественное наследование - это тупик, по которому можно спуститься во многих случаях, и слишком легко рано или поздно выстрелить себе в ногу.
Сокол

1
Позволяет упростить. Если мой интерфейс реализует две функции Display и Comment, и у меня есть класс, который их реализует. Тогда почему бы мне не удалить интерфейс и не использовать функции напрямую. Я хочу сказать, что они просто предоставляют вам названия функций, которые необходимо реализовать. Если кто-то может вспомнить эти функции, то зачем создавать интерфейс
Pankaj Upadhyay

9
@Pankaj, если это все, для чего вам нужен интерфейс, не используйте его. Вы используете интерфейс, когда у вас есть программа, которая хочет не знать ни о каком аспекте класса и получать к нему доступ по его базовому типу, то есть интерфейсу. Им не нужно знать ни один из подклассов, просто он относится к типу интерфейса. Таким образом, вы можете затем вызвать реализованный метод подкласса через ссылку на интерфейс объекта. Это базовое наследство и дизайн вещи. Без него вы могли бы также использовать C. Даже если вы явно не используете его, фреймворк не будет работать без него.
Джонатан Хенсон

12

Вы, вероятно, использовали foreachи нашли, что это довольно полезный инструмент итерации. Знаете ли вы, что для работы требуется интерфейс IEnumerable ?

Это, безусловно, конкретный случай, говорящий о полезности интерфейса.


5
На самом деле, foreach не требует IEnumerable: msdn.microsoft.com/en-us/library/9yb8xew9%28VS.80%29.aspx
Мэтт Х

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

2
Интерфейсы являются множественным наследованием, о чем часто забывают. Однако они не допускают множественного наследования поведения и состояния. Миксины или черты допускают множественное наследование поведения, но не разделяемое состояние, которое вызывает проблемы: en.wikipedia.org/wiki/Mixin
Мэтт H

@Pankaj, оффтоп, но не против, если я спрошу, какой у тебя родной язык? «Держать ухо другой рукой» - отличная идиома, и мне было любопытно, откуда она взялась.
Кевин

3
@Iceman. LOL .... Я из Индии. И здесь это общая идиома, которая отражает выполнение легких дел трудным способом.
Панкадж Упадхяй,

11

Интерфейсы предназначены для кодирования объектов, как вилка для бытовой проводки. Вы бы припаяли радио прямо к вашей домашней проводке? Как насчет вашего пылесоса? Конечно, нет. Вилка и розетка, в которую она вписывается, образуют «интерфейс» между проводкой вашего дома и устройством, которому требуется питание. Ваша домашняя проводка должна ничего не знать об устройстве, кроме того, что она использует трехконтактную заземленную вилку и требует электропитания при 120 В переменного тока <= 15 А. И наоборот, устройство не требует никаких тайных знаний о том, как устроен ваш дом, кроме того, что оно имеет одно или несколько трехконтактных розеток, удобно расположенных, которые обеспечивают напряжение 120 В переменного тока <= 15 А.

Интерфейсы выполняют очень похожую функцию в коде. Объект может объявить, что конкретная переменная, параметр или возвращаемый тип имеет тип интерфейса. Интерфейс не может быть создан непосредственно с помощью newключевого слова, но мой объект может быть задан, или найти реализацию того интерфейса, с которым ему нужно будет работать. Когда объект имеет свою зависимость, ему не нужно точно знать, что это за зависимость, он просто должен знать, что он может вызывать методы X, Y и Z для зависимости. Реализации интерфейса не должны знать, как они будут использоваться, они просто должны знать, что они должны предоставлять методы X, Y и Z с конкретными сигнатурами.

Таким образом, абстрагируя несколько объектов за одним и тем же интерфейсом, вы предоставляете общий набор функциональных возможностей любому потребителю объектов этого интерфейса. Вам не нужно знать, что объект является, например, List, Dictionary, LinkedList, OrderedList или чем-то еще. Поскольку вы знаете, что все они IEnumerables, вы можете использовать методы IEnumerable, чтобы проходить каждый элемент в этих коллекциях по одному. Вам не нужно знать, что выходным классом является ConsoleWriter, FileWriter, NetworkStreamWriter или даже MulticastWriter, который принимает другие типы пишущих; все, что вам нужно знать, это то, что все они пишут IWriters (или что-то в этом роде), и поэтому у них есть метод «Write», в который вы можете передать строку, и эта строка будет выведена.


7

Хотя программисту (поначалу, по крайней мере) очень удобно иметь множественное наследование, это почти тривиальное упущение, и вы (в большинстве случаев) не должны полагаться на множественное наследование. Причины этого сложны, но если вы действительно хотите узнать об этом, рассмотрите опыт работы с двумя наиболее известными (по индексу TIOBE ) языками программирования, которые его поддерживают: C ++ и Python (соответственно 3-й и 8-й).

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

Для C ++, поищите в Google «иерархию алмазов C ++» и посмотрите на то уродство, которое собирается вас охватить. C ++ профессионалы знают, как использовать множественное наследование. Все остальные обычно просто играют, не зная, какими будут результаты. Еще одна вещь, которая показывает, насколько полезны интерфейсы, это то, что во многих случаях классу может потребоваться полностью переопределить поведение своего родителя. В таких случаях родительская реализация не нужна и обременяет дочерний класс только памятью для личных переменных родителя, что может не иметь значения в возрасте C #, но имеет значение при выполнении встроенного программирования. Если вы используете интерфейс, эта проблема не существует.

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

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

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


6

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

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


5

Я лично люблю абстрактный класс и использую его больше, чем интерфейс. Основное отличие заключается в интеграции с интерфейсами .NET, такими как IDisposable, IEnumerable и т. Д., А также с взаимодействием COM. Кроме того, для написания интерфейса требуется чуть меньше усилий, чем для абстрактного класса, и класс может реализовать более одного интерфейса, в то время как он может наследовать только от одного класса.

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

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

Я широко использовал интерфейсы при написании плагинов, используя пространство имен System.ComponentModel. Они очень пригодятся.


1
Очень хорошо поставлено! Полагаю, вам понравится моя статья об абстрактных классах. Абстракция это все .
Стивен Джеурис

5

Я могу сказать, что я отношусь к этому. Когда я впервые начал изучать OO и C #, у меня тоже не было Интерфейсов. Это нормально. Нам просто нужно натолкнуться на то, что поможет вам оценить удобство интерфейсов.

Позвольте мне попробовать два подхода. И простите меня за обобщения.

Попробуй 1

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

Вы спрашиваете: «Эй, ты родился в Соединенных Штатах?» Это наследство.

Или вы спрашиваете: «Эй, ты говоришь по-английски»? Это интерфейс.

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

Можно полагаться на наследство. Если вам нужен кто-то, кто говорит по-английски, любит чай и любит футбол, вам лучше попросить британца. :)

Попробуй 2

Хорошо, давайте попробуем другой пример.

Вы используете разные базы данных, и вам нужно реализовать абстрактные классы для работы с ними. Вы передадите свой класс какому-нибудь классу от поставщика БД.

public abstract class SuperDatabaseHelper
{
   void Connect (string User, string Password)
}

public abstract class HiperDatabaseHelper
{
   void Connect (string Password, string User)
}

Вы говорите, множественное наследование? Попробуйте это в приведенном выше случае. Ты не можешь Компилятор не будет знать, какой метод Connect вы пытаетесь вызвать.

interface ISuperDatabaseHelper
{
  void Connect (string User, string Password)
}

interface IHiperDatabaseHelper
{
   void Connect (string Password, string User)
}

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

public class MyDatabaseHelper : ISuperDatabaseHelper, IHiperDatabaseHelper
{
   IHiperDataBaseHelper.Connect(string Password, string User)
   {
      //
   }

   ISuperDataBaseHelper.Connect(string User, string Password)
   {
      //
   }

}

Заключение

Примеры не самые лучшие, но я думаю, что это важно.

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


Первая попытка - вот что дало мой голос.
osundblad

1
Теперь я полностью использую аналогию с американским и английским спикерами. Это фантастика.
Брайан Бетчер

Объясняется проще! Фантастика.
Аймал Хан

4

Есть две основные причины:

  1. Отсутствие множественного наследования. Вы можете наследовать от одного базового класса и реализовать любое количество интерфейсов. Это единственный способ «сделать» множественное наследование в .NET.
  2. COM-совместимость. Все, что нужно будет использовать «старыми» технологиями, должно иметь определенные интерфейсы.

Точка 1 - определенно причина и причина, разработанная самими разработчиками Microsoft
Pankaj Upadhyay

1
@Pankja На самом деле, они взяли идею интерфейса из Java (как хорошая часть возможностей C #).
Оливер Вейлер

3

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


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

3

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


2

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

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


2

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


1

Реализация в реальном мире:

Вы можете привести объект в качестве типа интерфейса:

IHelper h = (IHelper)o;
h.HelperMethod();

Вы можете создать список интерфейса

List<IHelper> HelperList = new List<IHelper>();

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


0

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

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

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

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

Например, вы можете заменить ...

Me.PublishDate.Clear()
Me.Subject.Clear()
Me.Body.Clear()

...с участием:

For Each ctl As IClear In Me.Controls.OfType(Of IClear)()
    ctl.Clear()
Next

Что звучит очень похоже на:

Слушай, Слушай! Всем ли кто разбирается в расчистке, пожалуйста Clearсейчас!

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


0

Ниже приведен псевдокод:

class MyClass{

    private MyInterface = new MyInterfaceImplementationB();

    // Code using Thingy 

}

interface MyInterface{

    myMethod();

}

class MyInterfaceImplementationA{ myMethod(){ // method implementation A } }

class MyInterfaceImplementationB{ myMethod(){ // method implementation B } }

class MyInterfaceImplementationC{ myMethod(){ // method implementation C } }

Последние классы могут быть совершенно разных реализаций.

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.