Я использовал для создания много абстрактных классов / методов. Затем я начал использовать интерфейсы.
Теперь я не уверен, что интерфейсы не делают абстрактные классы устаревшими.
Вам нужен полностью абстрактный класс? Вместо этого создайте интерфейс. Вам нужен абстрактный класс с некоторой реализацией в нем? Создайте интерфейс, создайте класс. Наследуй класс, реализуй интерфейс. Дополнительным преимуществом является то, что некоторым классам может не понадобиться родительский класс, а просто будет реализован интерфейс.
Итак, являются ли абстрактные классы / методы устаревшими?
object-oriented
architecture
inheritance
interfaces
Борис Янков
источник
источник
Ответы:
Нет.
Интерфейсы не могут обеспечить реализацию по умолчанию, абстрактные классы и методы могут. Это особенно полезно, чтобы избежать дублирования кода во многих случаях.
Это также действительно хороший способ уменьшить последовательную связь. Без абстрактного метода / классов вы не можете реализовать шаблон шаблона шаблона. Я предлагаю вам взглянуть на эту статью в Википедии: http://en.wikipedia.org/wiki/Template_method_pattern
источник
Существует абстрактный метод, так что вы можете вызывать его из своего базового класса, но реализовать его в производном классе. Итак, ваш базовый класс знает:
Это достаточно хороший способ реализовать отверстие в среднем шаблоне без знания производного класса о действиях по настройке и очистке. Без абстрактных методов вам придется полагаться на производный класс, реализующий
DoTask
и запоминающий вызовbase.DoSetup()
иbase.DoCleanup()
все время.редактировать
Кроме того, спасибо Deadalnix за публикацию ссылки на шаблонный шаблон , который я описал выше, фактически не зная имени. :)
источник
public void DoTask(Action doWork)
Fruit
и ваш производный классApple
, вы хотите позвонитьmyApple.Eat()
, а неmyApple.Eat((a) => howToEatApple(a))
. Кроме того, вы не хотитеApple
звонитьbase.Eat(() => this.howToEatMe())
. Я думаю, что чище просто переопределить абстрактный метод.Нет, они не устарели.
На самом деле, между абстрактными классами / методами и интерфейсами есть неясное, но принципиальное отличие.
если набор классов, в которых должен использоваться один из них, имеет общее поведение, которое они разделяют (я имею в виду связанные классы), то переходите к абстрактным классам / методам.
Пример: clerk, Officer, Director - все эти классы имеют общую CalculateSalary (), используют абстрактные базовые классы. CalculateSalary () может быть реализован по-разному, но есть некоторые другие вещи, например, GetAttendance (), которые имеют общее определение в базовом классе.
Если между вашими классами нет ничего общего (несвязанные классы в выбранном контексте) между ними, но есть действие, которое сильно отличается по реализации, тогда переходите к интерфейсу.
Пример: корова, скамейка, машина, классы, не связанные с телепопой, но Isortable может быть там для сортировки их в массив.
Это различие обычно игнорируется при подходе с полиморфной точки зрения. Но я лично чувствую, что есть ситуации, когда один является подходящим, чем другой по причине, описанной выше.
источник
В дополнение к другим хорошим ответам, между интерфейсами и абстрактными классами есть фундаментальное различие, которое никто специально не упомянул, а именно, что интерфейсы гораздо менее надежны и, следовательно, накладывают гораздо большую нагрузку на тестирование, чем абстрактные классы. Например, рассмотрим этот код C #:
Я гарантирую, что есть только два пути кода, которые мне нужно проверить. Автор Frobbit может полагаться на тот факт, что фроббер красный или зеленый.
Если вместо этого мы говорим:
Теперь я абсолютно ничего не знаю о последствиях этого звонка Фробу. Мне нужно быть уверенным, что весь код на Frobbit устойчив к любой возможной реализации IFrobber , даже реализациям людей, которые некомпетентны (плохи) или активно враждебны ко мне или моим пользователям (намного хуже).
Абстрактные классы позволяют избежать всех этих проблем; используй их!
источник
Вы сами говорите:
это звучит много работы по сравнению с «наследовать абстрактный класс». Вы можете сделать работу для себя, подойдя к коду с точки зрения «пуристов», но я нахожу, что у меня уже достаточно дел, не пытаясь увеличить свою рабочую нагрузку без практической пользы.
источник
Как я прокомментировал пост @deadnix: Частичные реализации являются анти-паттерном, несмотря на то, что шаблон шаблона их формализует.
Чистое решение для этого примера шаблона шаблона в Википедии :
Это решение лучше, потому что оно использует композицию вместо наследования . Шаблон шаблона вводит зависимость между реализацией правил Monopoly и реализацией того, как должны запускаться игры. Однако это две совершенно разные обязанности, и нет веских причин для их объединения.
источник
Нет. Даже предлагаемая вами альтернатива включает использование абстрактных классов. Кроме того, поскольку вы не указали язык, я собираюсь сразу сказать, что универсальный код в любом случае лучше, чем хрупкое наследование. Абстрактные классы имеют значительные преимущества перед интерфейсами.
источник
Абстрактные классы не являются интерфейсами. Это классы, которые не могут быть созданы.
Но тогда у вас будет неабстрактный бесполезный класс. Абстрактные методы необходимы для заполнения функциональной дыры в базовом классе.
Например, учитывая этот класс
Как бы вы реализовали эту базовую функциональность в классе, который не имеет ни того,
Frob()
ни другогоIsFrobbingNeeded
?источник
Я - создатель фреймворка сервлетов, в котором абстрактные классы играют существенную роль. Я бы сказал больше, мне нужны полу абстрактные методы, когда метод должен быть переопределен в 50% случаев, и я хотел бы, чтобы предупреждение от компилятора об этом методе не было переопределено. Я решаю проблему, добавляя аннотации. Возвращаясь к вашему вопросу, есть два разных варианта использования абстрактных классов и интерфейсов, и пока никто не устарел.
источник
Я не думаю, что они устарели из-за интерфейсов, но они могут быть устаревшими по шаблону стратегии.
Основное использование абстрактного класса - отложить часть реализации; сказать, «эта часть реализации класса может быть сделано по-другому».
К сожалению, абстрактный класс заставляет клиента делать это с помощью наследования . Тогда как шаблон стратегии позволит вам достичь того же результата без какого-либо наследования. Клиент может создавать экземпляры вашего класса, а не всегда определять свои собственные, и «реализация» (поведение) класса может изменяться динамически. У модели стратегии есть дополнительный плюс, что поведение может быть изменено во время выполнения, а не только во время разработки, и также имеет значительно более слабую связь между вовлеченными типами.
источник
Обычно я сталкиваюсь с гораздо большими проблемами обслуживания, связанными с чистыми интерфейсами, чем с ABC, даже с ABC, использующими множественное наследование. YMMV - не знаю, может быть, наша команда просто использовала их неадекватно.
Тем не менее, если мы используем реальную аналогию, насколько полезны чистые интерфейсы, полностью лишенные функциональности и состояния? Если в качестве примера я использую USB, то это достаточно стабильный интерфейс (я думаю, что мы сейчас находимся на USB 3.2, но он также поддерживает обратную совместимость).
Тем не менее, это не интерфейс без состояния. Это не лишено функциональности. Это больше похоже на абстрактный базовый класс, чем на чистый интерфейс. Это на самом деле ближе к конкретному классу с очень конкретными функциональными требованиями и требованиями к состоянию, с единственной абстракцией, которая подключается к порту и является единственной заменяемой частью.
В противном случае это была бы просто «дыра» в вашем компьютере со стандартизированным форм-фактором и гораздо более слабыми функциональными требованиями, которые ничего бы не сделали сами по себе, пока каждый производитель не придумал свое собственное оборудование, чтобы заставить эту дыру что-то делать, и в этот момент он становится гораздо более слабым стандартом и не более чем «дырой» и спецификацией того, что он должен делать, но не является центральным условием того, как это сделать. Между тем у нас может оказаться 200 различных способов сделать это после того, как все производители оборудования попытаются придумать свои собственные способы прикрепления функциональности и состояния к этой «дыре».
И в этот момент у нас могут быть определенные производители, которые создают другие проблемы по сравнению с другими. Если нам нужно обновить спецификацию, у нас может быть 200 различных конкретных реализаций USB-портов с совершенно разными способами решения спецификации, требующей обновления и тестирования. Некоторые производители могут разрабатывать фактические стандартные реализации, которые они разделяют между собой (ваш аналогичный базовый класс, реализующий этот интерфейс), но не все. Некоторые версии могут быть медленнее, чем другие. Некоторые могут иметь лучшую пропускную способность, но худшую задержку или наоборот. Некоторые могут использовать больше энергии аккумулятора, чем другие. Некоторые могут отключиться и не работать со всем оборудованием, которое должно работать с USB-портами. Некоторые могут потребовать подключения к работе ядерного реактора, который имеет тенденцию вызывать радиационное отравление.
И это то, что я нашел лично с чистыми интерфейсами. Могут быть случаи, когда они имеют смысл, например, просто смоделировать форм-фактор материнской платы по сравнению с корпусом процессора. Аналогии форм-фактора, действительно, в значительной степени не содержат состояний и лишены функциональности, как в случае аналогичной «дыры». Но я часто считаю огромной ошибкой для команд считать, что это как-то лучше во всех случаях, даже не близко.
Наоборот, я думаю, что гораздо больше случаев будет решаться лучше с помощью ABC, чем интерфейсов, если это два варианта, если ваша команда не настолько гигантская, что на самом деле желательно иметь аналог, эквивалентный 200 конкурирующим реализациям USB, а не один центральный стандарт для поддерживать. В бывшей команде я был, я на самом деле должен был бороться трудно просто ослабить на стандарт кодирования, чтобы азбуке и множественное наследование, и, главным образом, в ответ на эти проблемы технического обслуживания, описанных выше.
источник