{

protected:

Car* mCar;

public:

CarDecorator(Car* car): mCar(car) {};

void setCar(Car* car) {mCar = car;}

...

virtual float getCost() {return mCar->getCost();}

virtual void addEngine(Engine* engine) {mCar->addEngine(engine);}

...

};

Как вы видите, базовый декоратор просто перенаправляет вызовы в объект mCar, который хранит, и кажется бесполезным. Но вся суть в классах, порожденных от него (см. листинг 4).

Листинг 4

class CarDecoratorLogger: public CarDecorator

{

...

virtual float getCost()

{

float retValue = CarDecorator::getCost();

LOG_TO_FILE(«getCost for %s returned %d», mCar->getDescription(), retValue);

return retValue;

}

virtual void addEngine(Engine* engine)

{

LOG_TO_FILE(«addEngine(%s) for %s», engine->getDescription(), mCar->getDescription());

CarDecorator::addEngine(engine);

}

...

};

Кроме добавления новых операций, декоратор часто используется для хранения состояния объекта или для добавления понятия состояния объектам, у которых его нет внутри. Например, мы можем отслеживать продвижение сборки автомобиля (см. листинг 5).

Листинг 5

class CarDecoratorProgressTracker: public CarDecorator

{

bool mHaveDoors;

bool mHaveEngine;

bool mHaveWheels;

...

virtual void addEngine(Engine* engine)

{

if (engine)

mHaveEngine = true;

CarDecorator::addEngine(engine);

}

virtual void addDoors(Door* doors, int doorsCount)

{

if (doorsCount && doors)

mHaveDoors = true;

CarDecorator::addDoors(doors, doorsCount);

}

...

virtual bool readyToMove()

{

return (mHaveDoors && mHaveEngine && mHaveWheels);

};

};

Теперь можно изменить поведение объекта Car, если везде хранить указатель не на него, а на CarDecorator. Создавая нужный CarDecorator, мы можем менять поведение всей иерархии объектов Car, не изменяя код в самих этих объектах и не создавая новые иерархии объектов, порожденных от Car.

«Фасад»

Шаблон «Фасад» (Facade) позволяет скрыть сложность системы, направив все возможные внешние вызовы через один объект-фасад, который просто делегирует эти вызовы соответствующим объектам системы.

Известно, что одна из основных характеристик сложности кода – это степень связанности (coupling), т. е. мера, определяющая, насколько жестко один элемент кода связан с другими элементами либо каким количеством данных о других элементах он обладает.

Элемент с низкой степенью связанности (слабосвязанный, low coupling) зависит от не слишком большого числа других элементов. Выражение «слишком много» зависит от контекста, и в каждом проекте это свое число.

Класс с высокой степенью связанности (или жестко связанный) зависит от множества других классов. Наличие таких классов нежелательно, поскольку оно приводит к возникновению многих проблем, – например, изменения в связанных классах приводят к локальным изменениям в данном классе, затрудняется также понимание каждого класса в отдельности и усложняется повторное использование, поскольку для этого требуется дополнительный анализ классов, с которыми связан данный класс.

Именно для уменьшения степени связанности с целой подсистемой и применяется паттерн «Фасад». Если у вас есть подсистема, которая часто меняется, и из-за этого вы хотите оградить клиентов этой системы от знания деталей ее реализации (уменьшить связность), то логичное решение – создать специальный класс-фасад, который будет предоставлять весь набор функций данной подсистемы. Таким образом, все клиенты будут общаться с подсистемой только посредством этого класса-фасада.

Например, предположим, что наш код для работы с автомобилями, описанный выше, – это только одна из подсистем огромной программы. И мы хотим оградить остальные подсистемы от частых изменений этой подсистемы для работы с автомобилями, так как мы знаем, что она часто меняется и будет меняться. Применим шаблон «Фасад» и создадим специальный класс CarSystemFacade (см. листинг 6).

Листинг 6

const int InvalidCarId = -1;

const int InvalidEngineId = -1;

...

class CarSystemFacade

{

...

typedef int CarId;

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату