Наследование, включение в C#

Когда несколько лет назад многие начали программировать на объектно-ориентированных языках, наследование считалось самым великолепным изобретением со времен бутерброда.

Фактически, многие люди рассматривали его как неотъемлемую и важнейшую часть объектно-ориентированного программирования.

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

В споры на эту тему были вовлечены многие люди в течение многих лет, и периодически эти споры принимали форму религиозных войн. Однако с истечением времени некоторые умные проектировщики стали замечать ловушки, присущие наследованию.

Выбор между интерфейсом и наследованием класса

Когда вы впервые открываете для себя наследование, то поначалу склонны злоупотреблять им. Это случается легко. И такие злоупотребления затрудняют понимание и сопровождение программных проектов, особенно на языках, подобных С++, которые поддерживают множественное наследование. Получающийся дизайн трудно адаптировать для будущих потребностей, что заставляет отбрасывать его и заменять совершенно новым.

В языках, поддерживающих только одиночное наследование, таких как С# и Java, разработчик вынужден более тщательно подходить к применению наследования.

Например, моделируя систему управления кадровыми ресурсами в компании XYZ, наивный дизайнер может завести классы вроде Payee (получатель платежа), Benef itsRecipient (получатель дохода) и Developer (разработчик). Затем, применив множественное наследование, он может представить составной класс наемного разработчика FulltimeDeveloper, унаследовав его от всех трех.

Как видите, это заставит нашего горе-дизайнера создать новый класс для представления разработчиков по контракту, который не наследуется от BenefitsRecipient. По мере роста системы быстро обнаруживаются недостатки в дизайне, когда структура наследования станет достаточно сложной и глубокой.

Теперь получится два класса для разных типов разработчиков, что затруднит управление таким дизайном. А теперь рассмотрим неудачную попытку решить ту же проблему на языке, поддерживающем только одиночное наследование.

Если внимательно присмотреться, обнаружится некоторая неоднозначность. В среде, где разрешено только одиночное наследование, нельзя, чтобы класс Developer наследовался одновременно от Payee и BenefitsRecipient. По этой причине не может быть двух иерархий в одном и том же дизайне.

Вам придется создать два разных варианта класса Developer — один для наследования от него FulltimeDeveloper, а другой — для наследования ContractDeveloper. Однако это будет пустой тратой времени. Что более важно, если требуется создавать две версии по существу одного и того же класса, то пропадает возможность многократного использования кода, а это является главным преимуществом наследования.

Более удачный подход состоит в том, чтобы иметь класс Developer, содержащий различные свойства, которые представляют определенные характеристики разработчиков внутри компании. Например, поддержка специфического интерфейса может характеризоваться поддержкой определенного свойства. Иерархия наследования с большим количеством уровней в глубину — явный признак того, что дизайн нуждается в переосмыслении.

Чтобы увидеть, что в действительности происходит здесь, давайте проанализируем, что именно означает для вас наследование. В действительности оно позволяет бесплатно сэкономить часть работы за счет наследования реализации. Есть существенное отличие между простым наследованием и наследованием реализации.

Хотя объектно-ориентированные языки, в том числе и С#, обычно используют сходный синтаксис для этих двух видов наследования, важно отметить, что классы, реализующие интерфейс, не получают никакой готовой реализации вообще. При использовании наследования, однако, вы не только наследуете общедоступный контракт базового класса, но также наследуете компоновку, или все его внутренности.

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

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100