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

         

Наследование с расширением


Определение: Наследование с Расширением

Наследование с расширением применимо, когда B вводит компоненты, не представленные в A и не применимые к прямым экземплярам A. Класс A должен быть эффективным.

Присутствие обоих вариантов - расширения и сужения (ограничения) - является одним из парадоксов наследования. Как отмечалось при обсуждении наследования, расширение применяется к компонентам, в то время как ограничение (понимаемое как специализация) применяется к экземплярам. Но это не устраняет парадокс.

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

class A feature a1: INTEGER end class B inherit A feature b1: REAL end

Рассмотрим каждый экземпляр класса A как одноэлементное множество (которое можно записать как <n>, где n целое), а каждый экземпляр B - как пару, содержащую целое и вещественное (например, пару <1, -2.5>). Множество пар MB не является подмножеством одноэлементного множества MA. Верно обратное, отношение "быть подмножеством" имеет место в обратном направлении, поскольку существует отображение один-к-одному между MA и множеством всех пар, имеющих данный второй элемент.

Обнаружение того факта, что отношение "быть подмножеством" не выполняется, делает наследование расширением довольно подозрительным. Например, в ранней версии уважаемой ОО-библиотеки (не от ISE) класс RECTANGLE был наследником SQUARE, в отличие от изучаемого нами способа. Причина простая: класс SQUARE имеет атрибут side; класс RECTANGLE наследует его, добавляя новый компонент other_side. Этот проект был подвергнут критике, он был пересмотрен с обращением наследования.

Но не следует исключать наследование с расширением как общую категорию. У нее есть эквивалент в математике, где специализация некоторого понятия происходит путем добавления новых операций. Такое происходит довольно часто и считается необходимым. Типичным примером является понятие кольца, представляющее специализацию понятия группы. В группе задана некоторая операция, назовем ее +, обладающая рядом свойств. Кольцо является группой, потому имеет ту же операцию + с теми же свойствами. Но в кольцо добавляется новая операция, скажем, *, со своими собственными свойствами. По сути это не отличается от введения нового атрибута классом наследником.

Соответствующая схема используется и при разработке ОО-ПО. Конечно, класс SQUARE должен быть наследником RECTANGLE, а не наоборот, но можно предложить легитимные примеры. Класс MOVING_POINT (в приложениях кинематики) может наследовать от чисто графического класса POINT и добавлять компонент speed, описывающую величину и направление скорости. Другой пример, в текстовом процессоре класс CHAPTER может наследовать от DOCUMENT, добавляя специфические свойства - текущую позицию лекции в книге и процедуру ее сохранения.



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