Я изучал и программировал на C # в течение некоторого времени. Но все же я не могу понять полезность интерфейсов. Они приносят слишком мало к столу. Кроме предоставления сигнатур функций, они ничего не делают. Если я могу вспомнить имена и подписи функций, которые должны быть реализованы, в них нет необходимости. Они существуют только для того, чтобы убедиться, что указанные функции (в интерфейсе) реализованы в наследующем классе.
C # - отличный язык, но иногда он дает вам ощущение, что сначала Microsoft создает проблему (не разрешая множественное наследование), а затем предлагает решение, которое довольно утомительно.
Это мое понимание, основанное на ограниченном опыте кодирования. Что вы думаете об интерфейсах? Как часто вы ими пользуетесь и что заставляет вас это делать?
источник
Ответы:
Верный. Это достаточно удивительное преимущество, чтобы оправдать эту функцию. Как уже говорили другие, интерфейс - это договорное обязательство по реализации определенных методов, свойств и событий. Неоспоримым преимуществом статически типизированного языка является то, что компилятор может проверить, действительно ли выполнен контракт, на который опирается ваш код.
Тем не менее, интерфейсы являются довольно слабым способом представления договорных обязательств. Если вы хотите более сильный и гибкий способ представления договорных обязательств, обратите внимание на функцию Code Contracts, которая поставлялась с последней версией Visual Studio.
Ну, я рад, что тебе нравится.
Все сложные программные разработки являются результатом сопоставления противоречивых функций друг с другом и попытки найти «слабое место», которое дает большие преимущества при небольших затратах. Из многолетнего опыта мы узнали, что языки, которые допускают множественное наследование для целей совместного использования реализации, имеют относительно небольшие преимущества и относительно большие затраты. Разрешение множественного наследования только на интерфейсах, которые не разделяют детали реализации, дает много преимуществ множественного наследования без большей части затрат.
источник
Assume
вызовов для случаев, таких как элементы массива или перечисления. После добавления всего и просмотра статически проверенного беспорядка, который я имел, я вернулся к управлению исходным кодом, потому что это снизило качество моего проекта.Так что в этом примере PowerSocket больше ничего не знает о других объектах. Все объекты зависят от мощности, предоставляемой PowerSocket, поэтому они реализуют IPowerPlug и при этом могут подключаться к нему.
Интерфейсы полезны, потому что они предоставляют контракты, которые объекты могут использовать для совместной работы, без необходимости знать что-либо друг о друге.
источник
Смысл интерфейсов не в том, чтобы помочь вам вспомнить, какой метод реализовать, он здесь для определения контракта . В примере foreach P.Brian.Mackey (который оказывается неправильным , но нам все равно), IEnumerable определяет контракт между foreach и любой перечисляемой вещью. В нем говорится: «Кем бы вы ни были, пока вы придерживаетесь контракта (реализуйте IEnumerable), я обещаю вам, что буду повторять все ваши элементы». И это здорово (для не динамического языка).
Благодаря интерфейсам вы можете добиться очень низкой связи между двумя классами.
источник
Интерфейсы - лучший способ поддерживать хорошо отделенные конструкции.
При написании тестов вы обнаружите, что конкретные классы не будут работать в вашей тестовой среде.
Пример: вы хотите протестировать класс, который зависит от класса службы доступа к данным . Если этот класс общается с веб-службой или базой данных - ваш модульный тест не будет выполняться в вашей тестовой среде (плюс он превратился в интеграционный тест).
Решение? Используйте интерфейс для службы доступа к данным и макетируйте этот интерфейс, чтобы вы могли проверить свой класс как единое целое.
С другой стороны, WPF и Silverlight вообще не играют с интерфейсами, когда дело доходит до связывания. Это довольно неприятная морщина.
источник
Интерфейсы являются основой (статического) полиморфизма! Интерфейс - это то, что имеет значение. Наследование не будет работать без интерфейсов, поскольку подклассы в основном наследуют уже реализованный интерфейс родителя.
Довольно часто. Все, что должно быть подключаемым, является интерфейсом в моих приложениях. Часто у вас есть другие несвязанные классы, которые должны обеспечивать такое же поведение. Вы не можете решить такие проблемы с наследованием.
Нужны разные алгоритмы для выполнения операций над одними и теми же данными? Используйте интерфейс ( см. Шаблон стратегии )!
Хотите использовать разные реализации списка? Код против интерфейса и вызывающей стороны не нужно беспокоиться о реализации!
Считается хорошей практикой (не только в ООП), чтобы кодировать интерфейсы целую вечность, по одной единственной причине: легко изменить реализацию, если вы понимаете, что она не соответствует вашим потребностям. Это довольно громоздко, если вы пытаетесь достичь этого только с множественным наследованием или все сводится к созданию пустых классов для обеспечения необходимого интерфейса.
источник
Вы, вероятно, использовали
foreach
и нашли, что это довольно полезный инструмент итерации. Знаете ли вы, что для работы требуется интерфейс IEnumerable ?Это, безусловно, конкретный случай, говорящий о полезности интерфейса.
источник
Интерфейсы предназначены для кодирования объектов, как вилка для бытовой проводки. Вы бы припаяли радио прямо к вашей домашней проводке? Как насчет вашего пылесоса? Конечно, нет. Вилка и розетка, в которую она вписывается, образуют «интерфейс» между проводкой вашего дома и устройством, которому требуется питание. Ваша домашняя проводка должна ничего не знать об устройстве, кроме того, что она использует трехконтактную заземленную вилку и требует электропитания при 120 В переменного тока <= 15 А. И наоборот, устройство не требует никаких тайных знаний о том, как устроен ваш дом, кроме того, что оно имеет одно или несколько трехконтактных розеток, удобно расположенных, которые обеспечивают напряжение 120 В переменного тока <= 15 А.
Интерфейсы выполняют очень похожую функцию в коде. Объект может объявить, что конкретная переменная, параметр или возвращаемый тип имеет тип интерфейса. Интерфейс не может быть создан непосредственно с помощью
new
ключевого слова, но мой объект может быть задан, или найти реализацию того интерфейса, с которым ему нужно будет работать. Когда объект имеет свою зависимость, ему не нужно точно знать, что это за зависимость, он просто должен знать, что он может вызывать методы X, Y и Z для зависимости. Реализации интерфейса не должны знать, как они будут использоваться, они просто должны знать, что они должны предоставлять методы X, Y и Z с конкретными сигнатурами.Таким образом, абстрагируя несколько объектов за одним и тем же интерфейсом, вы предоставляете общий набор функциональных возможностей любому потребителю объектов этого интерфейса. Вам не нужно знать, что объект является, например, List, Dictionary, LinkedList, OrderedList или чем-то еще. Поскольку вы знаете, что все они IEnumerables, вы можете использовать методы IEnumerable, чтобы проходить каждый элемент в этих коллекциях по одному. Вам не нужно знать, что выходным классом является ConsoleWriter, FileWriter, NetworkStreamWriter или даже MulticastWriter, который принимает другие типы пишущих; все, что вам нужно знать, это то, что все они пишут IWriters (или что-то в этом роде), и поэтому у них есть метод «Write», в который вы можете передать строку, и эта строка будет выведена.
источник
Хотя программисту (поначалу, по крайней мере) очень удобно иметь множественное наследование, это почти тривиальное упущение, и вы (в большинстве случаев) не должны полагаться на множественное наследование. Причины этого сложны, но если вы действительно хотите узнать об этом, рассмотрите опыт работы с двумя наиболее известными (по индексу TIOBE ) языками программирования, которые его поддерживают: C ++ и Python (соответственно 3-й и 8-й).
В Python поддерживается множественное наследование, но программисты почти не понимают его, и заявить, что вы знаете, как оно работает, означает прочитать и понять эту статью на тему: Порядок разрешения методов . Что-то еще, что произошло в Python, это то, что интерфейсы вроде как попали в язык - Zope.Interfaces.
Для C ++, поищите в Google «иерархию алмазов C ++» и посмотрите на то уродство, которое собирается вас охватить. C ++ профессионалы знают, как использовать множественное наследование. Все остальные обычно просто играют, не зная, какими будут результаты. Еще одна вещь, которая показывает, насколько полезны интерфейсы, это то, что во многих случаях классу может потребоваться полностью переопределить поведение своего родителя. В таких случаях родительская реализация не нужна и обременяет дочерний класс только памятью для личных переменных родителя, что может не иметь значения в возрасте C #, но имеет значение при выполнении встроенного программирования. Если вы используете интерфейс, эта проблема не существует.
В заключение, интерфейсы, на мой взгляд, являются неотъемлемой частью ООП, поскольку они обеспечивают выполнение контракта. Множественное наследование полезно в ограниченных случаях, и обычно только для парней, которые знают, как его использовать. Таким образом, если вы новичок, то именно вы страдаете от отсутствия множественного наследования - это дает вам больше шансов не ошибиться .
Исторически сложилось так, что идея интерфейса уходит корнями гораздо раньше, чем спецификации Microsoft на C #. Большинство людей считают C # обновлением по сравнению с Java (в большинстве случаев) и догадываются, откуда C # получил свои интерфейсы - Java. Протокол - это более старое слово для того же понятия, и он намного старше, чем .NET.
Обновление: теперь я вижу, что мог бы ответить на другой вопрос - почему интерфейсы вместо множественного наследования, но это выглядело как ответ, который вы искали. Кроме того, в ОО-языке должен быть хотя бы один из двух, а остальные ответы охватили ваш оригинальный вопрос.
источник
Мне сложно представить чистый объектно-ориентированный код C # без использования интерфейсов. Вы используете их всякий раз, когда хотите обеспечить доступность определенных функций, не заставляя классы наследоваться от определенного базового класса, и это позволяет вашему коду иметь соответствующий уровень (низкой) связи.
Я не согласен с тем, что множественное наследование лучше, чем наличие интерфейсов, даже до того, как мы начнем утверждать, что множественное наследование сопряжено со своими собственными проблемами. Интерфейсы являются основным инструментом для обеспечения полиморфизма и повторного использования кода, что еще нужно?
источник
Я лично люблю абстрактный класс и использую его больше, чем интерфейс. Основное отличие заключается в интеграции с интерфейсами .NET, такими как IDisposable, IEnumerable и т. Д., А также с взаимодействием COM. Кроме того, для написания интерфейса требуется чуть меньше усилий, чем для абстрактного класса, и класс может реализовать более одного интерфейса, в то время как он может наследовать только от одного класса.
Тем не менее, я считаю, что большинство вещей, для которых я бы использовал интерфейс, лучше обслуживаются абстрактным классом. Чистые виртуальные функции - абстрактные функции - позволяют вам заставить разработчика определить функцию, аналогичную тому, как интерфейс вынуждает разработчика определять всех его членов.
Однако вы обычно используете интерфейс, когда не хотите навязывать определенный класс суперклассу, в то время как вы используете абстрактный класс, чтобы иметь повторно используемый дизайн, который уже в основном реализован.
Я широко использовал интерфейсы при написании плагинов, используя пространство имен System.ComponentModel. Они очень пригодятся.
источник
Я могу сказать, что я отношусь к этому. Когда я впервые начал изучать OO и C #, у меня тоже не было Интерфейсов. Это нормально. Нам просто нужно натолкнуться на то, что поможет вам оценить удобство интерфейсов.
Позвольте мне попробовать два подхода. И простите меня за обобщения.
Попробуй 1
Скажем, вы носитель английского языка. Вы отправляетесь в другую страну, где английский не является родным языком. Тебе нужна помощь. Вам нужен кто-то, кто может вам помочь.
Вы спрашиваете: «Эй, ты родился в Соединенных Штатах?» Это наследство.
Или вы спрашиваете: «Эй, ты говоришь по-английски»? Это интерфейс.
Если вы заботитесь о том, что он делает, вы можете положиться на интерфейсы. Если вы заботитесь о том, что есть, вы полагаетесь на наследство.
Можно полагаться на наследство. Если вам нужен кто-то, кто говорит по-английски, любит чай и любит футбол, вам лучше попросить британца. :)
Попробуй 2
Хорошо, давайте попробуем другой пример.
Вы используете разные базы данных, и вам нужно реализовать абстрактные классы для работы с ними. Вы передадите свой класс какому-нибудь классу от поставщика БД.
Вы говорите, множественное наследование? Попробуйте это в приведенном выше случае. Ты не можешь Компилятор не будет знать, какой метод Connect вы пытаетесь вызвать.
Теперь есть кое-что, с чем мы можем работать - по крайней мере, в C # - где мы можем реализовать интерфейсы явно.
Заключение
Примеры не самые лучшие, но я думаю, что это важно.
Вы только «получите» интерфейсы, когда почувствуете их необходимость. До них вы будете думать, что они не для вас.
источник
Есть две основные причины:
источник
Использование интерфейсов помогает системе оставаться разъединенной и, таким образом, ее легче реорганизовать, изменить и развернуть. Это основополагающая концепция объектно-ориентированной ортодоксальности, и я впервые узнал об этом, когда гуру C ++ создали «чистые абстрактные классы», которые вполне эквивалентны интерфейсам.
источник
Сами по себе интерфейсы не очень полезны. Но когда они реализуются конкретными классами, вы видите, что это дает вам возможность иметь одну или несколько реализаций. Бонус заключается в том, что объекту, использующему интерфейс, не нужно знать, как обстоят дела с фактической реализацией - это называется инкапсуляция.
источник
Они в основном используются для повторного использования кода. Если вы кодируете интерфейс, вы можете использовать другой класс, который наследуется от этого интерфейса и не нарушает все.
Кроме того, они очень полезны в веб-сервисах, где вы хотите, чтобы клиент знал, что делает класс (чтобы они могли его использовать), но не хотите давать ему реальный код.
источник
Будучи молодым программистом / разработчиком, просто изучая C #, вы можете не увидеть полезности интерфейса, потому что вы можете писать свои коды, используя ваши классы, и код работает нормально, но в реальном сценарии создание масштабируемого, надежного и обслуживаемого приложения предполагает использование некоторые архитектуры и шаблоны, которые могут быть сделаны возможными только при использовании интерфейса, например, внедрение зависимостей.
источник
Реализация в реальном мире:
Вы можете привести объект в качестве типа интерфейса:
Вы можете создать список интерфейса
С этими объектами вы можете получить доступ к любому из методов или свойств интерфейса. Таким образом, вы можете определить интерфейс для вашей части программы. И строить логику вокруг этого. Тогда кто-то еще может реализовать ваш интерфейс в своих бизнес-объектах. Если BO меняются, они могут изменить логику для компонентов интерфейса и не требовать изменения логики для вашей части.
источник
Интерфейсы обеспечивают модульность в стиле плагина, предоставляя классам механизм для понимания (и подписки) на определенные виды сообщений, которые доставляет ваша система. Я уточню.
В своем приложении вы решаете, что всякий раз, когда форма загружается или перезагружается, вы хотите, чтобы все вещи, которые она хранит, были очищены. Вы определяете
IClear
интерфейс, который реализуетClear
. Кроме того, вы решаете, что всякий раз, когда пользователь нажимает кнопку сохранения, форма должна пытаться сохранить свое состояние. Таким образом, все, что соблюдает,ISave
получает сообщение о сохранении своего состояния. Конечно, практически говоря, большинство интерфейсов обрабатывают несколько сообщений.Что отличает интерфейсы, так это то, что общее поведение может быть достигнуто без наследования. Класс, реализующий данный интерфейс, просто понимает, как вести себя при выдаче команды (командное сообщение) или как реагировать при запросе (сообщение запроса). По сути, классы в вашем приложении понимают сообщения, которые предоставляет ваше приложение. Это облегчает построение модульной системы, в которую можно подключать вещи.
В большинстве языков есть механизмы (например, LINQ ) для запроса того, что соответствует интерфейсу. Обычно это поможет вам устранить условную логику, потому что вам не придется сообщать разным вещам (которые не обязательно являются производными от одной и той же цепочки наследования), как вести себя подобным образом (согласно конкретному сообщению). Вместо этого вы собираете все, что понимает определенное сообщение (соблюдает интерфейс), и публикуете сообщение.
Например, вы можете заменить ...
...с участием:
Что звучит очень похоже на:
Таким образом, мы можем программно избежать указаний каждой вещи очищать себя. И когда в будущем добавляются очищаемые элементы, они просто отвечают без какого-либо дополнительного кода.
источник
Ниже приведен псевдокод:
Последние классы могут быть совершенно разных реализаций.
Если множественное наследование невозможно, наследование навязывает реализацию родительского класса, делая вещи более жесткими. Программирование с использованием интерфейсов, с другой стороны, может сделать ваш код или структуру очень гибкими. Если вы когда-нибудь сталкивались с делом, в котором хотели бы поменяться классами в цепочке наследования, вы поймете, почему.
Например, инфраструктура, которая предоставляет Reader, изначально предназначенный для чтения данных с диска, может быть повторно реализована для выполнения чего-то такого же характера, но совершенно другим способом. Например, интерпретировать азбуку Морзе.
источник