Использует разделение для эффективной поддержки большого числа мелких объектов.
Назначение
Использует разделение для эффективной поддержки множества мелких объектов.
Применимость
Эффективность паттерна приспособленец во многом зависит от того, как и где он используется. Применяйте этот паттерн, когда выполнены все нижеперечисленные условия:
- в приложении используется большое число объектов;
- из-за этого накладные расходы на хранение высоки;
- большую часть состояния объектов можно вынести вовне;
- многие группы объектов можно заменить относительно небольшим количеством разделяемых объектов, поскольку внешнее состояние вынесено;
- приложение не зависит от идентичности объекта. Поскольку объекты-приспособленцы могут разделяться, то проверка на идентичность возвратит "истину" для концептуально различных объектов.
Структура
Участники
- Flyweight - приспособленец - объявляет интерфейс, с помощью которого приспособленцы могут получать внешнее состояние или как-то воздействовать на него;
- ConcreteFlyweight - конкретный приспособленец - реализует интерфейс Flyweight и добавляет при необходимости внутреннее состояние. Объект класса ConcreteFlyweight должен быть разделяемым. Любое сохраняемое им состояние должно быть внутренним, т.е. не зависящим от контекста;
- UnsharedConcreteFlyweight - неразделяемый конкретный приспособленец - не все подклассы обязательно должны быть разделяемыми. Интерфейс Flyweight допускает разделение, но не навязывает его. Часто у объектов UnsharedConcreteFlyweight на некотором уровне структуры приспособленца есть потомки в виде объектов класса ConcreteFlyweight.
- FlyweightFactory - фабрика приспособленцев:
- создает объекты-приспособленцы и управляет ими;
- обеспечивает должное разделение приспособленцев. Когда клиент запрашивает приспособленца, объект ConcreteFlyweight предоставляет существующий экземпляр или создает новый, если готового еще нет.
- Client - клиент:
- хранит ссылки на обного или нескольких приспособленцев;
- вычисляет или хранит внешнее состояние приспособленцев;
Результаты
При использовании приспособленцев не исключены затраты на передачу, поиск или вычисление внутреннего состояния, особенно если раньше оно хранилось как внутреннее. Однако такие расходы с лихвой компенсируются экономией памяти за счет разделения объектов-приспособленцев.
Экономия памяти возникает по ряду причин:
- уменьшение общего числа экземпляров;
- сокращение объема памяти, необходимого для хранения внутреннего состояния;
- вычисление а не хранение внешнего состояния (если это действительно так).
Чем выше степень разделения приспособленцев, тем существеннее экономия. С увеличением объема разделяемого состояния экономия также возрастает. Самого большого эффекта удается добиться когда суммарный объем внутренней и внешней информации о состоянии велик, а внешнее состояние вычисляется, а не храниться. Тогда разделение уменьшает стоимость хранения внутреннего состояния, а за счет вычислений сокращается память, отводимая на внешнее состояние.
Паттерн приспособленец часто применяется с компоновщиком для представления в виде иерархической структуры в виде графа с разделяемыми листовыми узлами. Из-за разделения указатель на родителя не может храниться в листовом узле-приспособленце, а должен передаваться ему как часть внешнего состояния. Это оказывает заметное влияние на способ взаимодействия объектов иерархии между собой.