Студопедия
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Паттерн Composite

Читайте также:
  1. Введение в паттерны проектирования
  2. Введение в паттерны проектирования
  3. Введение в паттерны проектирования
  4. Введение в паттерны проектирования
  5. Введение в паттерны проектирования
  6. Введение в паттерны проектирования
  7. Гдд Паттерны поведения
  8. Глава 1. Введение в паттерны проектирования
  9. Глава 3. Порождающие паттерны
  10. Глава 4. Структурные паттерны

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

Иногда, проявив изобретательность, удается перенести в класс Component операцию, которая, на первый взгляд, имеет смысл только для составных объектов. Например, интерфейс для доступа к потомкам является фунда­ментальной частью класса Composite, но вовсе не обязательно класса Leaf. Однако если рассматривать Leaf как Component, у которого никогда не бы­вает потомков, то мы можем определить в классе Component операцию до­ступа к потомкам как никогда не возвращающую потомков. Тогда подклас­сы Leaf могут использовать эту реализацию по умолчанию, а в подклассах Composite она будет переопределена, чтобы возвращать потомков. Операции для управления потомками довольно хлопотны, мы обсудим их в следующем разделе;

а объявление операций для управления потомками. Хотя в классе Composite реализованы операции Add и Remove для добавления и удаления потомков, но для паттерна компоновщик важно, в каких классах эти операции объяв­лены. Надо ли объявлять их в классе Component и тем самым делать до­ступными в Leaf, или их следует объявить и определить только в классе Composite и его подклассах?

Решая этот вопрос, мы должны выбирать между безопасностью и прозрач­ностью:

- если определить интерфейс для управления потомками в корне иерархии
классов, то мы добиваемся прозрачности, так как все компоненты удает­
ся трактовать единообразно. Однако расплачиваться приходится безопас­
ностью, поскольку клиент может попытаться выполнить бессмысленное
действие, например добавить или удалить объект из листового узла;

- если управление потомками сделать частью класса Composite, то безо­
пасность удастся обеспечить, ведь любая попытка добавить или удалить
объекты из листьев в статически типизированном языке вроде C++ бу­
дет перехвачена на этапе компиляции. Но прозрачность мы утрачиваем,
ибо у листовых и составных объектов оказываются разные интерфейсы.

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

Можно, например, объявить в классе Component операцию Composite* GetComposite (). Класс Component реализует ее по умолчанию, возвра­щая нулевой указатель. А в классе Composite эта операция переопределе­на и возвращает указатель this на сам объект:


 

Структурные паттерны

class Composite;

class Component { public:

virtual Composite* GetComposite() { return 0; }

j

class Composite: public Component { public:

void Add(Component*);

// ■ ■ ■

virtual Composite* GetComposite(} { return this; }

class Leaf: public Component { I.

Благодаря операции Get Composite можно спросить у компонента, явля­ется ли он составным. К возвращаемому этой операцией составному объек­ту допустимо безопасно применять операции Add и Remove:

Composite* aComposite = new Composite; Leaf* aLeaf = new Leaf;

Component * aComponent; Composite* test;

aComponent = aComposite; if (test = aComponent->GetComposite()) { test->Add(new Leaf);

aComponent = aLeaf;

if (test = aComponent->GetComposite()) {

test->Add(new Leaf); // не добавит лист

Аналогичные проверки на принадлежность классу Composite в C++ вы­полняют и с помощью оператора dynamic_cast.

Разумеется, при таком подходе мы не обращаемся со всеми компонентами единообразно, что плохо. Снова приходится проверять тип, перед тем как предпринять то или иное действие.

Единственный способ обеспечить прозрачность - это включить в класс Component реализации операций Add и Remove по умолчанию. Но появит­ся новая проблема: нельзя реализовать Component:: Add так, чтобы она никогда не приводила к ошибке. Можно, конечно, сделать данную опера­цию пустой, но тогда нарушается важное проектное ограничение; попытка




Дата добавления: 2015-09-11; просмотров: 78 | Поможем написать вашу работу | Нарушение авторских прав

Обсуждение порождающих паттернов | Глава 4. Структурные паттерны | Паттерн Adapter | Структурные паттерны | Результаты | Паттерн Adapter | Структурные паттерны | Мотивация | Применимость | Структурные паттерны |


lektsii.net - Лекции.Нет - 2014-2025 год. (0.007 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав