Приспособленец (Flyweight) относиться к классу структурных паттернов. Он используется для эффективной поддержки множества мелких объектов.
В некоторых приложения использование множества мелких объектов могло бы оказаться весьма полезным, однако прямая реализация ведет к чудовищному перерасходу ресурсов. Попробую объяснить это на примере интернет магазина, в котором мы будем продавать крутые дизайнерские подушки. С покупателями у нас не возникает проблем (так как подушки крутые), и список продаж все растет и растет. А так как это тешит наше самолюбие, вводить постраничность мы не спешим. И вот наступает тот момент, когда страница грузится достаточно долго, чтобы мы успели не только заскучать, но и совершить вечерний променад. Мы достигаем точки кипения и с большой неохотой пытаемся оптимизировать нашу архитектуру. Она из себя представляет собой набор объектов-продаж, включающего объект-покупатель и набор объектов-товаров. Где каждый объект-товар это совокупность таких параметров, как: артикул подушки, цвет подушки, цена, скидка.
Получается, что на каждую запись о продаже инстанцируется минимум 2 объекта (в зависимости от количества купленных подушек). В текущей реализации, порождение такого количества объектов излишне. Путем не сложных манипуляций можно объединить объект-покупатель и объект-товар в один объект продажа. На этом можно не останавливаться и свести все к одному объекту продажи.
Внося такие изменения мы не только теряем в гибкости и расширяемости, но и можем погрязнуть в устранении зависимостей. Решением этой проблемы может стать паттерн приспособленец.
Паттерн приспособленец позволяет повторно использовать мелкие объекты в различном контексте. В итоге мы сможем использовать в различных объектах-продажах одни и теже объекты-покупатели и объекты-товары. Как это работает на примере объекта-товара. У нас есть набор параметров (артикул подушки, цвет подушки, цена, скидка), которые полностью характеризуют этот товар. Соответственно, если у нас было несколько покупателей, которые выбрали одну и туже модель подушки, одного и того же цвета и попали под одну и туже скидку, то итоговые объекты-товары будут полностью идентичны. В итоге мы можем использовать один и тот же объект сразу в нескольких местах, что позволит сэкономить нам немного памяти. При достаточно большом количестве мелких объектов с малым количеством различающихся признаков, мы сможем получить весьма существенную экономию ресурсов. Итак, как структурно выглядит паттерн:
Где:
FlyweightFactory — модифицированный паттерн фабрика, для создания приспособленцев. Методу getFlyweight передаются признаки, по которым будет создан новый, либо найден и возвращен уже готовый объект.
Flyweight — абстрактный класс приспособленцев
ConcreteFlyweight — конкретная реализация приспособленца, которая будет замещать собой одинаковые мелкие объекты.
UnsharedFlyweight — реализация приспособленца, который не может быть разделен.
[php]
class FlyweightFactory
{
protected static $_flyweigths = array();
/**
* @param string $key
* @return Flyweight
*/
public static function getFlyweight($key)
{
// key может быть не только строкой, но и любым другим типом,
// в таком случае необходим иной способ поиска созданных приспособленцев
if (! isset(self::$_flyweigths[$key])) {
// здесь могут быть условия, когда создавать обычного приспособленца,
// а когда возвращать неделимого
self::$_flyweigths[$key] = new ConcreteFlyweight();
}
return self::$_flyweigths[$key];
}
}
abstract class Flyweight
{
/**
* @var mixed внутреннее состояние
*/
protected $_intrinsicState = null;
/**
* @param mixed $extrinsicState
* внешнее состояние, передаваемое в приспособленец (контекст)
*/
public function Operation($extrinsicState)
{
//…
}
}
class ConcreteFlyweight extends Flyweight {}
class UnsharedFlyweight extends Flyweight {}
[/php]
Паттерн приспособленец зачастую используется вместе c паттерном компоновщик, для реализации иерархической структуры в виде ациклического направленного графа с разделяемыми листовыми вершинами.