Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
412
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

135

Единственное реальное различие между наследованием и использованием функции обратного вызова или исходящего (outgoing) интерфейса, такого как ICustomize, состоит в том, что в последнем случае необходимо вручную присоединить клиент к компоненту. Эту технику мы рассмотрим в гл. 13. Используя ее, необходимо быть осторожным с циклическим подсчетом ссылок. В общем случае ICustomize реализуют как часть своего собственного компонента с отдельным счетчиком ссылок.

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

Теперь у Вас все есть. В сущности, все, что дает наследование реализации, можно заново воссоздать с помощью интерфейсов, включения и агрегирования. Ясно, что наследование реализации С++ более привычно по сравнению с решением СОМ, которое представлено на рис. 8-11. Однако наследование реализации С++ требует доступа к исходному коду базового класса, а это означает, что при изменении базового класса программу придется перекомпилировать. В компонентной архитектуре, где компоненты постоянно и независимо друг от друга изменяются, а исходные коды недоступны, перекомпиляция невозможна. Делая повторное применение компонентов аналогичным простому использованию, СОМ ослабляет взаимозависимость между данным компонентом и компонентом, который он специализирует.

Клиент

Компонент

 

Клиент использует IX

IX

Компонент вызывает

 

 

 

 

интерфейс настройки,

 

 

который позволяет

ICustomize

Клиент вызывает

клиенту настроить его

ICustomize

реализацию IX

 

Реализация клиентом

 

 

ICustomize включает

Компонент настройки по

Компонент предоставляет

или агрегирует

компонент настройки по

умолчанию

компонент настройки,

умолчанию,

 

который реализует

предоставляемый

ICustomize

интерфейс ICustomize по

данным компонентом

умолчанию

Рис. 8-11 Компонент предоставляет реализацию исходящего интерфейса по умолчанию

Резюме

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

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

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

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

В этой главе мы научились повторному применению компонентов. В следующей главе будет рассмотрен другой вариант: вместо повторного применения компонентов мы будем повторно применять код на С++. Мы реализуем базовые классы для IUnknown и IClassFactory, от которых смогут наследоваться наши компоненты.

От всех этих разговоров о повторном применении у меня разыгрался аппетит. Наверное, пора узнать, насколько на самом деле съедобны миллионеры. Говорят, они хрустят на зубах.

Соседние файлы в предмете Программирование на C++