typedef int EngineId;
// Добавит машину в систему и вернет ее идентификатор
CarId createCar(const std::string& carType)
{
Car* car = CarFactory::create(carType);
if (!car)
return InvalidCarId;
CarManager::instance(). addCar(car);
return car->getId();
}
// Удалит машину
bool removeCar(CarId carId)
{
Car* car = CarManager::instance(). getCar(carId);
if (!car)
return false;
CarManager::instance(). removeCar(car);
delete car;
return true;
}
// Вернет стоимость автомобиля с идентификатором car
float getCarCost(CarId carId)
{
Car* car = CarManager::instance(). getCar(carId);
if (!car)
return 0;
return CarManager::instance(). getCostCalculator()->
calculateCost(car);
}
// Добавит двигатель engineType к автомобилю
// с идентификатором car
EngineId addEngineToCar(CarId carId, const std::string&
engineType)
{
Car* car = CarManager::instance(). getCar(carId);
if (!car)
return InvalidEngineId;
Engine* engine = EngineFactory::instance().
create(engineType);
if (!engine)
return InvalidEngineId;
car->addEngine(engine);
return engine->getId();
}
// Вернет полный список параметров двигателя
bool getEngineParameters(EngineId engine, EngineParams&
params)
{
Engine* engine = EngineFactory::instance().
create(engineType);
if (!engine)
return false;
params.power = engine->getPower();
params.fuelConsumption = engine->getFuelConsumption();
...
return true;
}
...
};
Как вы видите, класс-фасад должен защищать клиента от любого знания о подсистеме, поэтому он вводит новые понятия, такие, как CarId и EngineId. Это сделано, чтобы клиенты ничего не знали про реальные иерархии классов Car и Engine, а работали с подсистемой посредством этих идентификаторов, что тоже снижает уровень связанности и создает устойчивый интерфейс.
Ясно, что для большой подсистемы такой класс-фасад окажется огромным, но зато это будет единственная точка связывания подсистемы с клиентским кодом. А значит, все внутренние изменения подсистемы будут проходить незаметно и безболезненно, без возможности разрушить интерфейс, используемый клиентами.
Кроме того, наличие такого класса-фасада позволяет полностью изменить (например, переписать с нуля) реализацию подсистемы, причем сделать это становится гораздо проще благодаря слабому связыванию с клиентским кодом.
«Приспособленец»
Паттерн «Приспособленец» (Flyweight) используется, если надо уменьшить число объектов в системе. Когда объектов становится так много, что накладные расходы превышают лимиты, например, на память, то надо найти способ, как хранить меньше объектов и иметь ту же функциональность.
Этого можно достичь, если вынести из объектов контекстнозависимые параметры и параметры состояния. Это позволит во много раз сократить число объектов, но добавит накладные расходы на передачу в них контекста, так как контекст теперь будет храниться у клиентов.
Например, предположим, что мы в каждом автомобиле моделируем все детали, в том числе болты. В итоге уже через несколько минут работы программы в ней имеются миллионы объектов типа Bolt. Через 1– 2 ч это уже может стать проблемой и даже привести к MemoryOverflow (см. листинг 7).
Листинг 7
class Bolt
{
BoltType mType; // тип болта
float mWeight; // масса болта
Car* mCar; // в какой машине установлен
bool mWellTwisted; // хорошо ли закручен
Position mPosition; // позиция в 3-D пространстве относительно центра авто
...
public:
Bolt(BoltType type, float weight, Car* car, bool wellTwisted, const Position& pos) {...};
virtual void draw()
{
Position pos = mCar->getPosition() + mPosition;
DrawSystem::instance(). drawBolt(mType, pos);
};