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


Подходит ли нам наследование видов?


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

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

Альтернативой наследованию типов служит выбор одного критерия в качестве первичного, он и будет руководить построением иерархии. Для учета других критериев следует использовать специальные компоненты класса. Стоит отметить, что современные зоологи и ботаники используют именно такой подход: их основной критерий классификации основан на реконструкции эволюционной истории, включающей деление на роды и виды. Значит ли это, что мы всегда имеем единый, бесспорный стандарт, руководящий нами при создании программистских таксономий?

Чтобы в нашем примере придерживаться единого критерия, мы могли бы принять решение, что тип работы служащего является более важным фактором, а статус контракта задать компонентом. Рассмотрим первую попытку введения в класс EMPLOYEE такого компонента:

is_permanent: BOOLEAN

Но такое решение накладывает серьезные ограничения. Расширяя возможности, приходим к варианту:

Permanent: INTEGER is unique Temporary: INTEGER is unique Contractor: INTEGER is unique ...

Но это означает, что мы сталкиваемся с явным перечислением, и лучшим подходом является введение класса WORK_CONTRACT, как правило, отложенного, имеющего потомков по числу видов контракта. Тогда мы сможем избежать явного разбора случаев в форме:

if is_permanent then ... else ... end

или

inspect contract_type when Permanent then ... when ... ... end

Как неоднократно говорилось, разбор случаев приводит к ряду проблем при появлении новых вариантов и нарушает важные принципы непрерывности, единого выбора, открытость-закрытость и так далее.
Вместо этого мы поставляем класс WORK_CONTRACT с отложенными компонентами, представляющими операции, зависящие от типа контракта, которые по-разному будут реализованы потомками. Большинству из этих компонентов будет необходим аргумент типа EMPLOYEE, представляющий служащего, к которому применяется операция, примерами операций могут быть hire (приглашение на работу) and terminate (увольнение).

Результирующая структура показана на рис. 6.14.

Эта схема, как вы заметили, почти идентична образцу проектирования с описателями, изучаемому ранее в этой лекции.

Такая техника может использоваться вместо наследования видов. Это усложняет структуру из-за введения независимой иерархии, нового атрибута (здесь contract) и соответствующего клиентского отношения. Преимущество ее в том, что по поводу иерархии не возникает вопросов. В то же время при наследовании видов абстракции требуют больших пояснений (служащий, рассматриваемый с позиций его специальности или контракта).


Рис. 6.14.  Многокритериальная классификация с независимой иерархией, построенной для клиента


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