Основы объектно-ориентированного проектирования

         

Наследование вариаций


(Читатели - не математики, добро пожаловать!) Перейдем теперь ко второму семейству категорий - наследованию вариаций.

Определение: Наследование вариаций типа и функций

Наследование вариаций применяется, если B переопределяет некоторые компоненты A; A и B являются оба либо отложенными, либо эффективными. Класс B не должен вводить никаких новых компонентов за исключением тех, что непосредственно необходимы переопределяемым компонентам. Здесь рассматриваются два случая:

  • Наследование вариаций функций: переопределения действуют на тела компонентов, но не на их сигнатуры.
  • Наследование вариаций типа: все переопределения являются переопределениями сигнатур.

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

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

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

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

Наследование вариации типа не является необходимым, когда начальная сигнатура использует закрепленные (like...) объявления.
Например, в классе SEGMENT интерактивного пакета для рисования можно ввести функцию:

perpendicular: SEGMENT is -- Сегмент, повернутый на 90 градусов ...Затем определим наследника DOTTED_SEGMENT, дающего графическое представление пунктирными, а не непрерывными линиями. В этом классе perpendicular должен возвращать результат типа DOTTED_SEGMENT, так что необходимо переопределить тип. Этого бы не требовалось, если бы изначально результат объявлялся как like Current. Так что, будь у вас доступ к источнику и его автору, можно было бы предложить модифицировать оригинал, не нанося ущерба существующим клиентам. Но если нет возможности модифицировать оригинал или по ряду причин закрепленное объявление не подходит оригиналу (вероятно, из-за потребностей других потомков), то возможность переопределить тип может стать палочкой-выручалочкой.

При наследовании функциональной вариации изменяются тела некоторых компонентов. Если, как обычно в таком случае, компонент уже эффективен, то это означает изменение реализации. Спецификация компонента, заданная утверждением, также может измениться. Также возможно, хотя и реже встречается, иметь функциональную вариацию между двумя отложенными классами, в этом случае будут меняться только утверждения. Это может повлечь изменения в некоторых функциях, отложенных или эффективных, связанных с утверждениями, или даже добавление новых компонентов.

Наследование функциональной вариации является прямым приложением принципа Открыт-Закрыт: мы хотим адаптировать существующий класс, не затрагивая оригинал (к коду которого мы можем и не иметь доступа) и его клиентов. Это может стать предметом злоупотреблений, некоей формой хакерства, перекручивая существующий класс, приспосабливая его для других целей. Во всяком случае это будет организованное хакерство, позволяющее избежать угроз модификации существующего ПО. Но если есть доступ к оригиналу, то предпочтительной может оказаться реорганизация иерархии наследования путем введения абстрактного класса, для которого как уже существующий класс A, так и новичок B будут его потомками или подходящими наследниками с равным статусом.


Содержание раздела