Я понимаю, что это очень простой вопрос, но интервьюер задал мне очень хитрый тон, и я был беспомощен :(
Я знаю только материальное или теоретическое определение интерфейса, а также реализовал его во многих проектах, над которыми работал. Но я действительно не понимаю, почему и чем это полезно.
В интерфейсе тоже ничего не понимаю. например, мы используем
conn.Dispose();
в блоке finally. Но я не вижу, что этот класс реализует или наследует класс IDisposable
interface ( SqlConnection
), я имею в виду. Мне интересно, как я могу просто назвать имя метода. Кроме того, я не понимаю, как работает метод Dispose, поскольку нам нужно реализовать тело функции с нашей собственной реализацией для всех методов интерфейса. Итак, как интерфейсы принимаются или называются контрактами? Эти вопросы крутились у меня в голове до сих пор, и, честно говоря, я никогда не видел ни одной хорошей темы, которая бы объясняла мои вопросы так, как я могу понять.
MSDN, как обычно, выглядит очень пугающе, и здесь нет ни одной четкой строки ( ребята, извините, кто занимается разработкой высокого уровня, я твердо уверен, что любой код или статья должны доходить до ума любого, кто его видит, поэтому, как и многие другие, MSDN не годится ).
Интервьюер сказал:
У него есть 5 методов, и он счастлив реализовать их в классе напрямую, но если вам нужно выбрать абстрактный класс или интерфейс, какой из них вы выберете и почему? Я ответил ему на все материалы, которые я читал в различных блогах, говоря о преимуществах и недостатках как абстрактного класса, так и интерфейса, но он не убежден, он пытается понять «Почему интерфейс» в целом. "Почему именно абстрактный класс" вообще, даже если я могу реализовать одни и те же методы только один раз и не собираюсь их менять.
Я не вижу, где в сети, я мог бы получить статью, которая бы четко объяснила мне об интерфейсах и их работе. Я один из тех многих программистов, которые до сих пор не знают об интерфейсах (я знаю теоретические знания и методы, которые я использовал), но не удовлетворены тем, что я их ясно понял.
SqlConnection
наследует,System.ComponentModel.Component
который реализуетIDisposable
.SqlConnection
реализоватьIDisposable
.Ответы:
Интерфейсы прекрасны, когда нужно создать что-то подобное:
В моем примере я мог бы быть разработчиком, который пишет
MyLogClass
, а другие разработчики могли бы создавать свои классы, и когда они хотели регистрироваться, они реализуют интерфейсIMyLogInterface
. Они спрашивали меня, что им нужно реализовать, чтобы использоватьWriteLog()
методMyLogClass
. Ответ они найдут в интерфейсе.источник
MyClass
иMyOtherClass
почему бы вам просто не позвонить,aClass.WriteLog()
зачем добавлять этот дополнительный шаг. РеализацияWriteLog()
будет разной для каждого из классов, но у вас уже есть объект, так зачем передавать его классу обработчика?MyLogClass
WriteLog
методу. Таким образом, его метод может обрабатывать любой объект, который реализуетIMyLogInterface
. Вот еще один интересный пост.Одна из причин, по которой я использую интерфейсы, заключается в том, что это увеличивает гибкость кода. Допустим, у нас есть метод, который принимает в качестве параметра объект типа класса Account, например:
Проблема заключается в том, что параметр метода фиксируется в отношении реализации учетной записи. Это нормально, если вам никогда не понадобится учетная запись другого типа. Возьмем этот пример, в котором вместо этого в качестве параметра используется интерфейс учетной записи.
Это решение не привязано к реализации, что означает, что я могу передать ему SuperSavingsAccount или ExclusiveAccount (оба реализуют интерфейс IAccount) и получить различное поведение для каждой реализованной учетной записи.
источник
Интерфейсы - это контракты, которым должны следовать разработчики. Абстрактные классы допускают контракты плюс общие реализации - чего не может быть в интерфейсах. Классы могут реализовывать и наследовать несколько интерфейсов. Классы могут расширять только один абстрактный класс.
Почему интерфейс
IDbCommand
естьSqlCommand
иOracleCommand
которые реализуют интерфейс определенными способами )Почему абстракция
источник
DataContracts
) в сборке .NET ( например, Contracts.Shared.dll ), чтобы потребители клиентов .NET могли легко взаимодействовать друг с другомChannelFactory
( избегая генерации кода с помощью добавления ссылки на службу и т. Д.). ) или с помощью добавления ссылки на службу сИтак, в этом примере PowerSocket ничего не знает о других объектах. Все объекты зависят от мощности, предоставляемой PowerSocket, поэтому они реализуют IPowerPlug и при этом могут подключаться к нему.
Интерфейсы полезны, потому что они предоставляют контракты, которые объекты могут использовать для совместной работы, не зная ничего друг о друге.
источник
Одним словом - из-за полиморфизма !
Если вы «Программируете для интерфейса, а не для реализации», вы можете вставлять различные объекты, которые имеют один и тот же интерфейс (тип), в метод в качестве аргумента. Таким образом, код вашего метода не связан с какой-либо реализацией другого класса, что означает, что он всегда открыт для работы с вновь созданными объектами того же интерфейса. (Принцип открытия / закрытия)
источник
В C # нет утиной печати - просто потому, что вы знаете, что определенный метод реализован в наборе конкретных классов, не означает, что вы можете относиться к ним одинаково в отношении вызова этого метода. Реализация интерфейса позволяет вам рассматривать все классы, реализующие его, как объекты одного и того же типа в отношении того, что определяет этот интерфейс.
источник
Я считаю, что много крови уже было пролито, задавая эти вопросы, и многие пытаются решить эту проблему, объясняя термины, подобные роботам, которые не может понять ни один нормальный человек.
Итак, во-первых. чтобы узнать, почему интерфейс и почему абстрактный, вам нужно узнать, для чего они нужны. Я лично узнал об этих двух при применении Factory Class. по этой ссылке вы найдете хорошие уроки
Теперь давайте исследуем базу по уже приведенной мной ссылке.
У вас есть класс транспортного средства, который может измениться по требованию пользователя (например, добавление грузовика , цистерны , самолета и т. Д.
и
и у обоих есть контракт IChoice, в котором просто говорится, что у моего класса должен быть метод Buy
Теперь вы видите, что этот интерфейс только применяет метод,
Buy()
но позволяет унаследованному классу решать, что делать, когда он его реализует. Это ограничение интерфейса, используя чисто интерфейс, вы можете в конечном итоге повторить некоторую задачу, которую мы можем реализовать автоматически, используя abstact. В нашем примере, скажем, при покупке каждого автомобиля действует скидка.Теперь, используя Factory Class, вы можете добиться того же, но, используя abstract, вы позволяете базовому классу выполнять
Buy()
метод.источник
С помощью интерфейса вы можете делать следующее:
1) Создавайте отдельные интерфейсы, которые предлагают различные варианты вашей реализации, что позволяет создать более целостный интерфейс.
2) Разрешить использование нескольких методов с одинаковыми именами между интерфейсами, потому что у вас нет конфликтующей реализации, только подпись.
3) Вы можете версировать и удалять свой интерфейс независимо от вашей реализации, обеспечивая выполнение контракта.
4) Ваш код может полагаться на абстракцию, а не на конкретизацию, что позволяет использовать интеллектуальную инъекцию зависимостей, включая внедрение тестовых макетов и т. Д.
Я уверен, что есть еще много причин, и это лишь некоторые из них.
Абстрактный класс позволяет вам иметь частично конкретную основу для работы, это не то же самое, что интерфейс, но имеет свои собственные качества, такие как возможность создания частичной реализации с использованием шаблона метода шаблона.
источник
В качестве реального образца ответа @ user2211290:
Оба они
Array
иList
имеют интерфейсIList
. Ниже у нас есть astring[]
и a,List<string>
и мы проверяем их оба одним методом с помощью IList :источник
Вы можете наследовать только от одного абстрактного класса. Вы можете наследовать от нескольких интерфейсов. Это определяет, что я использую в большинстве случаев.
Преимущество абстрактного класса в том, что у вас может быть базовая реализация. Однако в случае IDisposable реализация по умолчанию бесполезна, поскольку базовый класс не знает, как правильно очистить вещи. Таким образом, интерфейс был бы более подходящим.
источник
И абстрактный класс, и интерфейс являются контрактами.
Идея контракта заключается в том, чтобы вы определяли какое-то поведение. Если вы говорите, что выполнили, вы согласились с контрактом.
Выбор абстрактного интерфейса есть.
Любой неабстрактный потомок абстрактного класса будет реализовывать контракт.
против
Любой класс, реализующий интерфейс, будет реализовывать контракт.
Таким образом, вы используете abstract, когда хотите указать какое-то поведение, которое должны реализовать все потомки, и сохранить себя, определяя отдельный интерфейс, но теперь все, что соответствует этому эффективно агрегированному контракту, должно быть потомком.
источник
Интерфейсы должны делать абстракцию (архетип) абстракции (классов) реальности (объектов).
Интерфейсы должны определять условия контракта без предоставления реализации, предоставляемой классами.
Интерфейсы имеют характеристики:
Интерфейсы - это артефакты времени разработки, указывающие на неподвижное поведение концепции, поскольку она единственная и статичная.
Классы - это артефакты времени реализации, определяющие мобильную структуру реальности при ее взаимодействии и перемещении.
Что такое интерфейс?
Наблюдая за кошкой, вы можете сказать, что это животное с четырьмя лапами, головой, хоботом, хвостом и шерстью. Вы видите, что он может ходить, бегать, есть и мяукать. И так далее.
Вы только что определили интерфейс с его свойствами и операциями. Таким образом, вы не определили никаких методов работы, а только функции и возможности, не зная, как все работает: вы определили способности и различия.
По сути, это еще не класс, хотя в UML мы называем его классом на диаграмме классов, потому что мы можем определить частные и защищенные члены, чтобы начать глубокое представление об артефакте. Не путайте здесь, потому что в UML интерфейс немного отличается от интерфейса в C #: он похож на частичную точку доступа к атому абстракции. Таким образом, мы сказали, что класс может реализовывать несколько интерфейсов. По сути, это одно и то же, но не потому, что интерфейсы в C # используются для абстрагирования абстракции и для ограничения этой абстракции как точки доступа. Это два разных использования. Таким образом, класс в UML представляет собой интерфейс полной связи с классом программирования, тогда как интерфейс UML представляет интерфейс разделения раздела класса программирования. На самом деле, диаграмма классов в UML не заботится о реализации, и все ее артефакты находятся на уровне интерфейса программирования. Хотя мы сопоставляем классы UML с классами программирования, это преобразование абстрактной абстракции в конкретную абстракцию. Есть тонкость, объясняющая дихотомию между областью дизайна и областью программирования. Итак, класс в UML - это класс программирования с точки зрения интерфейса программирования с учетом внутренних скрытых вещей.
Интерфейсы также позволяют имитировать множественное наследование, когда оно недоступно неудобным образом. Например, класс cat будет реализовывать интерфейс cat, производный от интерфейса животного. Этот класс cat также будет реализовывать эти интерфейсы: ходить, бегать, есть и издавать звук. Это компенсирует отсутствие множественного наследования на уровне класса, но каждый раз, когда вам нужно все заново реализовать, вы не можете учитывать реальность в лучшем случае, как это делает сама реальность.
Чтобы понять это, мы можем обратиться к объектному кодированию Pascal, где вы определяете в модуле интерфейс и разделы реализации. В интерфейсе вы определяете типы, а в реализации вы реализуете тип:
Здесь раздел интерфейса соответствует дизайну класса UML, в то время как типы интерфейсов, таким образом, другие.
Итак, в нашем бизнесе у нас есть одно слово, интерфейс , для обозначения двух разных, но похожих вещей, и это источник путаницы.
Также в C #, например, программные интерфейсы позволяют компенсировать отсутствие истинного универсального полиморфизма в открытых типах без реального достижения цели, потому что вы потеряли возможность использования строго типизированного кода.
В конце концов, интерфейсы необходимы для того, чтобы несовместимые системы могли обмениваться данными, не беспокоясь о реализации и управлении объектами в памяти, как это было в (распределенной) общей объектной модели.
Что такое класс?
После определения редукции реальности с внешней точки зрения вы можете затем описать ее с внутренней точки зрения: это класс, в котором вы определяете обработку данных и управление сообщениями, чтобы позволить реальности, которую вы инкапсулировали, ожить и взаимодействовать благодаря к объектам, использующим экземпляры.
Итак, в UML вы реализуете фрактальное погружение в колеса механизма и описываете состояния, взаимодействия и так далее, чтобы иметь возможность реализовать абстракцию фрагмента реальности, с которым вы хотите работать.
Таким образом, абстрактный класс в некотором смысле эквивалентен интерфейсу с точки зрения компилятора.
Больше информации
Протокол (объектно-ориентированное программирование)
C # - Интерфейсы
C # - Классы
источник
Позвольте рассказать вам о летающих тостерах.
Конечно, существует множество ситуаций, когда вы можете построить работающую программную систему, вообще не объявляя и не реализуя какие-либо интерфейсы: любой объектно-ориентированный проект программного обеспечения может быть реализован с использованием только классов.
С другой стороны, любая программная система также может быть реализована на языке ассемблера или, еще лучше, в машинном коде. Причина, по которой мы используем механизмы абстракции, заключается в том, что они, как правило, упрощают работу. Интерфейсы - это такой механизм абстракции.
Так уж получилось, что существуют определенные нетривиальные объектно-ориентированные проекты, которые намного проще реализовать, если вы используете интерфейсы, что интерфейсы практически становятся необходимыми в этих случаях.
Эти нетривиальные конструкции связаны с множественным наследованием, которое в его «истинной» форме - это когда класс наследуется не только от одного базового класса, но от двух или более базовых классов. Эта истинная форма невозможна в C #, но до появления таких языков, как C # и Java, правилом был C ++, который полностью поддерживал истинное множественное наследование. К сожалению, истинное множественное наследование оказалось не очень хорошей идеей, потому что оно чрезвычайно усложняет дизайн языка, а также порождает различные проблемы, например знаменитую «проблему алмаза». (См. Ответ Дж. Фрэнсиса «В чем именно заключается проблема множественного наследования?» )
Таким образом, если кто-то хочет создать класс «летающий тостер», он унаследует его от какого-то существующего класса «тостер», а также от некоторого существующего класса «летающий». Проблема, с которой они, вероятно, столкнулись, заключалась в том, что источником питания класса тостеров, вероятно, была стенная розетка, в то время как источником питания класса летательных аппаратов, вероятно, был корм для голубей, и в результате новый класс либо как-то есть оба, иначе было бы неясно, какой из них. (Проблема с бриллиантом.)
Создатели таких языков, как C # и Java, решили не допускать истинного множественного наследования, чтобы сохранить простоту языка и избежать ловушек, подобных проблеме бриллианта. Однако некоторая форма множественного наследования по-прежнему необходима (или, по крайней мере, очень желательна), поэтому в этих языках они ввели интерфейсы как средство поддержки меньшей формы множественного наследования, избегая при этом проблем и сложности настоящего множественного наследования.
В этой меньшей форме множественного наследования вам не разрешается иметь класс, наследующий более чем от одного базового класса, но вы можете по крайней мере наследовать от одного или нескольких интерфейсов. Итак, если вы хотите создать летающий тостер, вы не можете наследовать как от какого-то существующего класса тостера, так и от какого-то существующего летающего класса, но вы можете наследовать от существующего класса тостера, а затем также предоставить летающий интерфейс, который вы реализуете самостоятельно, возможно, используя любые средства, которые вы уже унаследовали от тостера.
Итак, если вы никогда не почувствуете необходимость создать класс, который объединяет два разных и несвязанных набора функций, вам не понадобится какая-либо форма множественного наследования, поэтому вам не нужно будет объявлять или реализовывать какие-либо интерфейсы.
источник
Интерфейсы позволяют разработчику классов сделать доступные методы очень понятными для конечного пользователя. Они также являются неотъемлемой частью полиморфизма.
источник
Я не буду публиковать определение интерфейса для абстрактного класса, потому что я думаю, что вы очень хорошо знаете теорию, и я предполагаю, что вы знаете принципы SOLID, поэтому давайте приступим к практике.
Как вы знаете, интерфейсы не могут иметь никакого кода, поэтому недостатки довольно просты для понимания.
если вам нужно инициализировать свойство вашего класса, предоставляя конструктор, или вы хотите предоставить часть реализации, абстрактный класс будет хорошо соответствовать интерфейсу, который не позволит вам сделать это.
Итак, в общем, вы должны предпочесть абстрактный класс интерфейсам, когда вам нужно предоставить конструктор или любой код клиенту, который будет наследовать / расширять ваш класс.
источник
Абстрактный класс создается для связанных сущностей, тогда как интерфейсы могут использоваться для несвязанных сущностей.
Например, если у меня есть две сущности, такие как Animal и Human, тогда я выберу интерфейс, где, как если бы мне нужно было подробно рассказать, скажем, Tiger, lion и хочу установить связь с Animal, тогда выберу Animal Abstract class
будет выглядеть ниже
источник