Являются ли интерфейсы избыточными при использовании абстрактов в качестве интерфейса?

#oop #design-patterns #interface #domain-driven-design #abstract-class

#ооп #шаблоны проектирования #интерфейс #доменно-ориентированный дизайн #абстрактный класс

Вопрос:

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

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

Краткие сведения:

  • Вопрос 1. В контексте ООП с языком, который поддерживает только одиночное наследование, при правильном проектировании, каковы некоторые виды использования интерфейсов над абстрактным классом?
  • Вопрос 2: В контексте DDD, если он спроектирован правильно, каковы возможности использования интерфейсов над абстрактным классом?

Примечание: я прочитал все перечисленные похожие вопросы, но, похоже, ни один из них не дал мне ответа. Если я пропустил один, пожалуйста, дайте мне знать.

Ответ №1:

Для вопроса 1: независимо от поддержки множественного наследования интерфейсы являются спецификациями контракта, абстрактные классы являются базовыми классами.

Интерфейсы предоставляют классу возможность указать набор возможностей (например, IDisposable, IEnumerable и т. Д.), И рекомендуется, Чтобы они подчинялись принципу разделения интерфейсов.

Абстрактные классы должны реализовывать концепцию, которая может быть расширена или которая может иметь разные реализации в зависимости от контекста (например, HttpContextBase, AbstractButton и т. Д.).

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

Что касается вопроса 2: в контексте интерфейсов DDD являются деталями реализации. Я осмелюсь сказать, что вы можете использовать DDD и не использовать интерфейсы или абстрактные классы или даже наследование. До тех пор, пока у вас четко определены ограниченные контексты, агрегаты, сущности и VOS.

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

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

Комментарии:

1. Ссылка на интернет-провайдера здесь действительно помогла. Спасибо!

Ответ №2:

Преимущество интерфейсов заключается именно в том, что нет множественного наследования. Используя интерфейс, вы можете разрешить таким классам, как Forms, UserControls, Components и т. Д., Участвовать во взаимодействиях, Которые в противном случае были бы затруднительными / невозможными.

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

Комментарии:

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

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

3. У меня есть небольшой фреймворк, который я использую, который имеет интерфейс под названием ILogicController. Этот интерфейс имеет методы, которые работают как часть конечного автомата. Если бы я преобразовал это в класс с именем AbstractLogicControlBase, то мои WinForms и UserControls больше не смогут участвовать в этой структуре. Форма, скажем, LoginForm, наследуется от System. Windows. Формы. Форма уже сформирована. он также не может наследовать от AbstractLogicControlBase.

Ответ №3:

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

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

Комментарии:

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