...

};

Ясно, что такие параметры, как mCar, mWellTwisted и mPosition, в данном примере, – это контекстно-зависимые параметры. Их можно вынести из объекта-болт в объект, который хранит болты. Может показаться, что это ничего не изменит – просто данные переместятся в другой объект, но на самом деле это не так. Например, объект типа Car может не хранить позиции всех своих болтов, а вычислять позиции по схеме автомобиля.

Применим паттерн «Приспособленец» и будем создавать только типы болтов, а не конкретные болты. Всю же недостающую контекстную информацию будем передавать параметрами.

class Bolt

{

BoltType mType; // тип болта

float mWeight; // масса болта

...

public:

Bolt(BoltType type) {...};

virtual void draw(Car* car, const Position& boltPosition)

{

Position pos = car->getPosition() + boltPosition;

DrawSystem::instance(). drawBolt(mType, pos);

};

...

};

Теперь в системе у нас будут сотни или тысячи, но не миллионы уникальных объектов класса Bolt. Но недостаток этого шаблона – увеличение накладных расходов на расчет и передачу контекстной информации в объекты.

«Заместитель»

Часто бывает необходимо прозрачно расширить возможности объекта. Например, создавать объект только при первом обращении к нему, добавить кэширование результатов или возможность работы с объектом удаленно (например, посредством RPC) либо сделать «умный» указатель с подсчетом ссылок. При этом хочется сделать это максимально прозрачно, чтобы клиенты, использующие этот объект, не заметили разницы. Для этого применяется паттерн «Заместитель» (Proxy).

Реализация этого паттерна очень проста. Например, предположим, что у нас в системе есть класс HighResolutionCarPicture, объекты которого хранятся в каждом объекте Car. При этом объекты HighResolutionCarPicture имеют большой размер, так как хранят текстуры. Предположим, в какой-то момент было установлено, что загрузка и инициализация проектов стали очень долгими, так как каждый раз эти текстуры загружаются на этапе инициализации объекта типа Car. Применим паттерн «Заместитель» и отложим инициализацию HighResolutionCarPicture до первого использования.

// Интерфейс.

class IHighResolutionCarPicture

{

...

virtual ErrorCode load(const std::string& fileName) = 0;

virtual Picture& getPicture() = 0;

...

};

// Реальный класс, реализующий функциональность

class HighResolutionCarPicture: public IHighResolutionCarPicture

{

...

Picture mPicture;

...

public:

...

virtual ErrorCode load(const std::string& fileName)

{

// загрузка текстуры из файла

...

}

virtual Picture& getPicture()

{

return mPicture;

}

...

};

// класс-заместитель, создающий реальный объект только

// при первом обращении

class HighResolutionCarPictureProxy: public

IHighResolutionCarPicture

{

HighResolutionCarPicture* mHighResolutionCarPicture;

void create()

{

if (!mHighResolutionCarPicture)

mHighResolutionCarPicture = new HighResolutionCarPicture();

}

...

public:

...

virtual ErrorCode load(const std::string& fileName)

{

create();

return mHighResolutionCarPicture->load(fileName);

}

virtual Picture& getPicture()

{

create();

return mHighResolutionCarPicture->getPicture();

}

...

};

Все клиенты, работающие с HighResolutionCarPicture, должны теперь использовать указатель на IHighResolutionCarPicture. Это позволит прозрачно использовать любой «Заместитель» так, что клиенты не заметят разницы.

Итак, в этой статье вы ознакомились с шаблонами проектирования из группы «Структурных паттернов». В следующей статье мы рассмотрим «Поведенческие паттерны» и на этом завершим знакомство с основным

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

0

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

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