.NET Framework Framework Guidelines может сказать несколько интересных вещей об интерфейсах и абстрактных классах.
В частности, они отмечают, что основным недостатком интерфейсов является их меньшая гибкость, чем у классов.когда дело доходит до эволюции API.После того, как вы отправите интерфейс, его члены будут фиксированы навсегда, и любые дополнения нарушат совместимость с существующими типами, которые реализуют этот интерфейс.Принимая во внимание, что доставка класса предлагает гораздо больше гибкости.Члены могут быть добавлены в любое время, даже после отправки первоначальной версии, если они не являются абстрактными.Любые существующие производные классы могут продолжать работать без изменений.В качестве примера приведен абстрактный класс System.IO.Stream
, представленный в Framework.Изначально он поставлялся без поддержки ожидания операций ввода-вывода, ожидающих ожидания, но версия 2.0 смогла добавить элементы, поддерживающие эту функцию, даже из существующих подклассов.
Таким образом, наличие соответствующего интерфейса для каждого абстрактного базового класса обеспечиваетнесколько дополнительных преимуществ.Интерфейс не может быть публично представлен, или вы вернулись на круги своя с точки зрения управления версиями.И если вы представляете только абстрактный базовый класс, то мало что дает, если интерфейс стоит на первом месте.
Кроме того, часто делается вывод в пользу интерфейсов, которые позволяют отделить контракт от реализации.Кшиштоф Квалина утверждает, что это утверждение является ложным: оно неверно предполагает, что вы не можете отделить контракты от реализации с использованием классов.Написав абстрактные классы, которые находятся в отдельной сборке от их конкретных реализаций, легко достичь тех же самых достоинств разделения.Он пишет:
Я часто слышу, как люди говорят, что интерфейсы определяют контракты.Я считаю, что это опасный миф.Сами по себе интерфейсы не определяют ничего, кроме синтаксиса, необходимого для использования объекта.Миф «интерфейс как контракт» заставляет людей поступать неправильно, пытаясь отделить контракты от реализации, что является отличной инженерной практикой.Интерфейсы отделяют синтаксис от реализации, что не очень полезно, и миф дает ложное чувство правильного проектирования.На самом деле контракт - это семантика, и она может быть хорошо выражена с помощью некоторой реализации.
В общем, предоставленное руководство ДОЛЖНО определять классы по интерфейсам .И снова Кшиштоф комментирует:
На протяжении трех версий .NET Framework я говорил об этом руководстве с довольно многими разработчиками в нашей команде.Многие из них, в том числе те, кто изначально не согласился с этим руководством, заявили, что сожалеют о том, что поставили какой-то API в качестве интерфейса.Я не слышал ни об одном случае, когда кто-то сожалел о том, что отправил класс.
Во втором руководстве утверждается, что один ДОЛЖЕН использовать абстрактные классы вместо интерфейсов для отделения контракта от реализаций .Дело в том, что правильно разработанные абстрактные классы по-прежнему допускают ту же степень разделения между контрактом и реализацией, что и интерфейсы.Таким образом, личная точка зрения Брайана Пепина такова:
Одна вещь, которую я начал делать, - это фактически заключить как можно больше контрактов с моим абстрактным классом.Например, я мог бы хотеть иметь четыре перегрузки для метода, где каждая перегрузка предлагает все более сложный набор параметров.Лучший способ сделать это - предоставить не виртуальную реализацию этих методов в абстрактном классе, и все реализации направляются к защищенному абстрактному методу, который обеспечивает фактическую реализацию.Делая это, вы можете написать всю скучную логику проверки аргументов один раз.Разработчики, которые хотят реализовать ваш класс, будут вам благодарны.
Возможно, лучше всего было бы вернуться к часто упоминаемому «правилу», согласно которому производный класс указывает отношение IS-A с базовым классом, тогда как класс, реализующий интерфейс, имеет CAN -До связи с этим интерфейсом. Чтобы сделать заявление, нужно всегда кодировать как интерфейс, так и абстрактный базовый класс, независимо от конкретных причин для этого, кажется, упускает суть.