Журнал PC Magazine/Russian Edition 01/2009
Шрифт:
Достоинства паттерна «Строитель» проявляются при создании сложных и больших иерархий объектов, поскольку у конкретных классов-строителей (потомков CarBuilder) есть возможность влиять на алгоритм конструирования объекта. Например, если когда-либо придется создавать автомобиль без двигателя, то метод addEngine для его разработчика просто будет пуст, тогда как логика работы CarDirector сохранится, поскольку все изменения будут локализованы в новом классе—потомке CarBuilder.
«Прототип»
Паттерн Prototype обычно применяется, когда можно
Для клонирования объектов нужно добавить в базовый класс метод клонирования, который обычно называют clone. Продолжим пример с автомобилями – расширим интерфейс класса Car (листинг 5).
Листинг 5
class Car
{
public:
virtual Car* clone const = 0;
virtual const char* getName const = 0;
virtual void setEngine(Engine* engine);
virtual Engine* getEngine const;
virtual void setWheels(Wheel* FR, Wheel* FL, Wheel* BR, Wheel* BL);
virtual void setFrontWheels(Wheel* FR, Wheel* FL);
virtual void setBackWheels(Wheel* BR, Wheel* BL);
...
};
Теперь в потомках класса Car нужно перезагрузить и реализовать этот метод, он должен создавать абсолютно идентичную новую копию объекта (см. листинг 6).
Листинг 6
class CarBMW5: public Car
{
public:
virtual Car* clone const
{
CarBMW5* car = new CarBMW5;
car->setEngine(getEngine->clone);
car->setFrontWheels(getWheelFR->clone, getWheelFL->clone);
car->setBackWheels(getWheelBR->clone, getWheelBL->clone);
...
return car;
}
...
};
Обратите внимание, что функция клонирования CarBMW5::clone вызывает функции клонирования для всех своих составных частей. Это стандартная практика: если использовать функцию клонирования в составном объекте, то нужно добавить ее во все объекты, которые он содержит. Таким образом, автомобиль легко клонирует себя, так как просто последовательно запускает процесс копирования всех составных частей и собирает из них новый автомобиль – свою полную копию.
Применений у этого паттерна может быть несколько, как уже было сказано выше. В случае с копированием объектов (Ctrl-C, Ctrl-V) мы будем иметь массив выделенных объектов и при нажатии на Ctrl-C просто создадим их копии, используя метод clone. А нажав на Ctrl-V, мы вставляем эти объекты в нужное место. Мы также можем заранее создать все возможные объекты (типы автомобилей) и поместить их в один массив. А потом легко создавать автомобили по имени: находим объект с нужным именем в массиве и вызываем его метод clone. Простой пример.
class CarFactory
{
std::vector<Car*> mCarTemplates;
public:
CarCreator
{
mCarTemplates.push_back(new CarBMW5);
mCarTemplates.push_back(new CarToyotaHiace);
mCarTemplates.push_back(new CarLadaKalina);
}
Car* create(const char* name)
{
for(size_t i = 0; i < mCarTemplates.size; ++i)
if (strcmp(mCarTemplates[i]->getName, name) == 0)
return mCarTemplates[i]->clone;
return NULL;
}
};
«Одиночка»
Паттерн Singleton
гарантирует, что объект какого-то класса будет создан только один раз. Это, пожалуй, самый спорный из всех шаблонов проектирования. Многие профессионалы объектно-ориентированного проектирования не рекомендуют применять этот паттерн, поскольку считают его обычным аналогом глобальных переменных. Самая простая реализация паттерна Singleton – это так называемый «синглтон Мейерса», где «Одиночка» представляет собой статический локальный объект (это решение небезопасно при работе с нитями).template<typename T> class Singleton
{
public:
static T& instance
{
// у класса T есть конструктор по умолчанию
static T theSingleInstance;
return theSingleInstance;
}
};
Чтобы класс стал «Одиночкой», его достаточно породить от Singleton.
Обычно всякие фабрики и контейнеры должны присутствовать в системе в единственном экземпляре, поэтому их разумно порождать от Singleton. Расширим класс CarFactory из предыдущего примера.
class CarFactory: public Singleton<CarFactory>
{
... дальше то же, что и в CarFactory из паттерна «Прототип»
};
Все обращения к такому объекту ведутся через метод Instance. Для создания автомобилей по названию нужно просто написать следующий код.
Car* bmw = CarFactory::instance. create(«BMW5»);
Car* hiace = CarFactory::instance. create(«ToyotaHiace»);
При этом объект типа CarFactory фактически будет создан в момент первого вызова метода instance, а удален только при выходе из программы.
Итак, мы рассмотрели в этой статье первую группу классических паттернов – «Порождающие». Их нужно знать и понимать очень хорошо, они встречаются наиболее часто, ведь создание объектов – неотъемлемая часть любого алгоритма.
Продолжение следует.
Обезопасим себя откражи личной информации
Мэттью Д. Саррел
Число покушений на личную информацию сокращается, но это не освобождает нас от необходимости защищаться.
Кража личной информации считается федеральным преступлением с 1998 г. Но изменилось ли в лучшую сторону положение дел? Несомненно, да. По данным обзора компании Javelin Strategy & Research, предоставленным организацией Privacy Rights Clearinghouse, за период с 2003 г. по 2007 г. число жертв краж личной информации, ежегодно совершаемых в США, сократилось примерно на 2 млн. (от 10,1 млн. до 8,4 млн.). А среднее время, необходимое для возмещения ущерба в каждом случае, уменьшилось от 40 ч в 2006 г. до 25 ч в 2007 г.