Первое наблюдение состоит в том, что клиентское отношение обычно допускает изменения, а наследование - нет. Сейчас мы должны с осторожностью обходиться с глаголами "быть" и "иметь", помогающими нам до сих пор характеризовать природу двух отношений между программными модулями. Правила для программ, как всегда, более точные, чем их двойники из обычного мира.
Одним из определяющих свойств наследования является то, что это отношение между классами, а не между объектами. Мы интерпретировали свойство "Класс B наследует от класса A" как "каждый объект B является объектом A". Следует помнить, что это свойство не в силах изменить никакой объект - только класс может достичь такого результата. Свойство характеризует ПО, но не его отдельное выполнение.
Для отношения клиента ограничения слабее. Если объект типа B имеет компонент типа A (либо подобъект, либо ссылку) вполне возможно изменить этот компонент - ограничением служит лишь система типов.
Заданное отношение между объектами может быть результатом как отношения наследования, так и клиентского отношения между классами. Важно различать, допускаются изменения или нет. Например, наша воображаемая структура объекта могла быть результатом отношения наследования между соответствующими классами:
Она могла быть точно так же получена через отношение клиента:
class SOFTWARE_ENGINEER_2 feature the_engineer_in_me: ENGINEER ... endФактически оно могло быть и таким:
class SOFTWARE_ENGINEER_3 feature the_truly_important_part_of_me: VOCATION ... endДля удовлетворения ограничений системы типов класс ENGINEER должен быть потомком класса VOCATION.
Строго говоря, последние два варианта представляют слегка отличную ситуацию. Если предположить, что ни один из заданных классов не является развернутым, то вместо подобъектов в последних двух случаях объекты "software engineer" будут содержать ссылки на объекты "engineer", как показано на рис.6.4. Введение ссылок, однако, не сказывается на сути нашего обсуждения. |