Обобщение

Типичный пример обобщения (generalization) включает индивидуаль­ного и корпоративного клиентов некоторой бизнес-системы. Несмотря на определенные различия, у них много общего. Одинаковые свойства можно поместить в базовый класс Customer (Клиент, супертип), при этом класс Personal Customer (Индивидуальный клиент) и класс Corpo­rate Customer (Корпоративный клиент) будут выступать как подтипы.

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

С точки зрения программного обеспечения очевидная интерпретация наследования выглядит следующим образом: Корпоративный клиент является подклассом класса Клиент. В основных объектно-ориентиро­ванных языках подкласс наследует всю функциональность суперклас­са и может переопределять любые методы суперкласса.

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


Вследствие полиморфизма Корпоративный клиент может реагировать на определенные команды не так, как другой Клиент, но вызывающий не должен беспокоиться об этом отличии. (Дополнительную информа­цию можно найти в главе «Liskov Substitution Principle (LSP)» (Прин­цип замещения Лисков) книги [30]).

Наследование представляет собой мощный механизм, но оно несет с собой много такого, что не всегда является необходимым для дости­жения замещаемости. Вот хороший пример: на заре существования языка Java многим разработчикам не нравилась реализация встроен­ного класса Vector (Вектор), и они хотели заменить его чем-нибудь по­легче. Однако единственным способом получения класса, способного заменить Vector, было создание его подкласса, что означало наследова­ние множества нежелательных данных и поведения.

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

Существует достаточное количество других механизмов, позволяю­щих создавать подтипы без создания подклассов. Примером может служить реализация интерфейса (стр. 96) и множество стандартных шаблонов разработки [21].


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: