«Абстрактный класс» и «интерфейс» являются похожими понятиями, причем интерфейс является более абстрактным из двух. Одним из отличительных факторов является то, что абстрактные классы предоставляют реализации методов для производных классов, когда это необходимо. Однако в C # этот дифференцирующий фактор был уменьшен недавним введением методов расширения, которые позволяют предоставлять реализации для методов интерфейса. Другим отличительным фактором является то, что класс может наследовать только один абстрактный класс (т. Е. Множественное наследование отсутствует), но он может реализовывать несколько интерфейсов. Это делает интерфейсы менее строгими и более гибкими. Итак, когда в C # мы должны использовать абстрактные классы вместо интерфейсов с методами расширения?
Примечательным примером модели метода interface + extension является LINQ, где функциональность запросов предоставляется для любого типа, который реализуется с IEnumerable
помощью множества методов расширения.
источник
Ответы:
Когда вам нужна часть класса для реализации. Лучший пример, который я использовал, это шаблонный шаблон.
Таким образом, вы можете определить шаги, которые будут предприняты при вызове Do (), не зная специфики того, как они будут реализованы. Производные классы должны реализовывать абстрактные методы, но не метод Do ().
Методы расширений не обязательно удовлетворяют части уравнения, которая должна быть частью класса. Кроме того, методы расширения iirc не могут быть (по-видимому) чем-то иным, кроме общедоступных.
редактировать
Вопрос более интересный, чем я изначально считал. После дальнейшего изучения Джон Скит ответил на такой вопрос в SO в пользу использования интерфейсов + методов расширения. Кроме того, потенциальным недостатком является использование отражения против иерархии объектов, разработанных таким образом.
Лично я испытываю затруднения, видя выгоду от изменения обычной практики в настоящее время, но также вижу, что в этом нет недостатков.
Следует отметить, что таким способом можно программировать на многих языках с помощью классов Utility. Расширения просто предоставляют синтаксический сахар, чтобы методы выглядели так, как будто они принадлежат классу.
источник
Do()
будут определены как метод расширения. И методы, оставленные для определения производных классов как,DoThis()
будут членами основного интерфейса. А с помощью интерфейсов вы можете поддерживать несколько реализаций / наследование. И посмотрите этоЭто все о том, что вы хотите моделировать:
Абстрактные классы работают по наследству . Будучи только специальные базовые классы, они моделируют некоторые есть- -relationship.
Например, собака является животным, таким образом , мы имеем
Поскольку нет смысла создавать универсальное животное (как бы оно выглядело?), Мы создаем этот
Animal
базовый класс,abstract
но он все еще является базовым классом. ИDog
класс не имеет смысла, не будучиAnimal
.Интерфейсы с другой стороны - это отдельная история. Они не используют наследование, но обеспечивают полиморфизм (который также может быть реализован с наследованием). Они не моделирующие есть- отношения, но больше он поддерживает .
Возьмите, например,
IComparable
- объект, который поддерживает сравнение с другим .Функциональность класса не зависит от интерфейсов, которые он реализует, интерфейс просто обеспечивает общий способ доступа к функциональности. Мы могли бы еще
Dispose
вGraphics
илиFileStream
без их реализацииIDisposable
. Интерфейс просто относится методы вместе.В принципе, можно добавлять и удалять интерфейсы, как расширения, не изменяя поведение класса, а просто расширяя доступ к нему. Вы не можете убрать базовый класс, поскольку объект станет бессмысленным!
источник
Animal
абстракцию. Это позволяет вам писатьabstract
функции, которые будут специализированы производными классами. Или, скорее, в терминах программирования - вероятно, нет смысла создавать aUserControl
, но как aButton
есть aUserControl
, поэтому мы имеем такой же тип отношений класс / базовый класс.Я только что понял, что я не использовал абстрактные классы (по крайней мере, не созданные) в течение многих лет.
Абстрактный класс - это несколько странный зверь между интерфейсом и реализацией. В абстрактных классах есть что-то, что вызывает у меня чувство паука. Я бы сказал, что никоим образом не следует «выставлять» реализацию интерфейса (или делать какие-либо привязки).
Даже если существует необходимость в общем поведении между классами, реализующими интерфейс, я бы использовал независимый вспомогательный класс, а не абстрактный класс.
Я бы пошел за интерфейсами.
источник
ИМХО, я думаю, что здесь происходит смешение понятий.
Классы используют определенный тип наследования, в то время как интерфейсы используют другой тип наследования.
Оба вида наследования важны и полезны, и у каждого есть свои плюсы и минусы.
Давайте начнем с самого начала.
История с интерфейсами начинается давно с C ++. В середине 1980-х годов, когда был разработан C ++, идея интерфейсов как другого типа еще не была реализована (это придет вовремя).
C ++ имел только один тип наследования, тип наследования, используемый классами, называемый наследованием реализации.
Чтобы иметь возможность применять рекомендацию GoF Book: «Для программирования для интерфейса, а не для реализации», C ++ поддерживает абстрактные классы и множественное наследование реализации, чтобы иметь возможность делать то, что интерфейсы в C # способны (и полезны!) Делать ,
C # представляет новый тип типа, интерфейсы и новый тип наследования, наследование интерфейса, чтобы предложить как минимум два различных способа поддержки «Программирование для интерфейса, а не для реализации», с одним важным предупреждением: только C # поддерживает множественное наследование с наследованием интерфейса (а не с наследованием реализации).
Итак, архитектурные причины интерфейсов в C # - это рекомендация GoF.
Я надеюсь, что это может помочь.
С уважением, Гастон
источник
Применение методов расширения к интерфейсу полезно для применения общего поведения между классами, которые могут использовать только общий интерфейс. Такие классы могут уже существовать и быть закрыты для расширений другими средствами.
Для новых разработок я предпочел бы использовать методы расширения на интерфейсах. Для иерархии типов методы расширения предоставляют средства для расширения поведения без необходимости открывать всю иерархию для модификации.
Однако методы расширения не могут получить доступ к частной реализации, поэтому на вершине иерархии, если мне нужно инкапсулировать частную реализацию за открытым интерфейсом, тогда абстрактный класс будет единственным способом.
источник
Я думаю, что в C # множественное наследование не поддерживается, и поэтому концепция интерфейса введена в C #.
В случае абстрактных классов множественное наследование также не поддерживается. Поэтому легко выбрать, использовать ли абстрактные классы или интерфейсы.
источник
Я нахожусь в процессе реализации класса Abstract в моем проекте просто потому, что C # не поддерживает операторы (неявные преобразования в моем случае) в интерфейсах.
источник