Flyweight (Легковес)¶
Категория: структурный паттерн.
Проблема¶
Программа создаёт огромное число похожих объектов, и повторяющиеся тяжёлые данные в каждом экземпляре расходуют слишком много памяти. Например, у миллионов деревьев уникальны координаты, но вид, цвет и текстура многократно повторяются.
Решение¶
Состояние разделяется на две части:
- внутреннее - повторяющееся, контекстно-независимое и обычно неизменяемое; оно хранится в общем объекте-легковесе;
- внешнее - уникальное для конкретного случая; оно хранится клиентом или объектом-контекстом и передаётся легковесу при выполнении операции.
Фабрика легковесов находит уже созданный объект с нужным внутренним состоянием или создаёт его один раз. Множество контекстов затем ссылаются на один экземпляр.
Структура¶
Flyweight- хранит разделяемое внутреннее состояние и выполняет операцию с переданным внешним состоянием.Context- хранит уникальное внешнее состояние и ссылку на легковес.FlyweightFactory- кеширует и переиспользует легковесы по ключу внутреннего состояния.Client- создаёт контексты и запрашивает легковесы у фабрики.
Когда применять¶
Только когда измерения показывают, что одновременно выполняются условия:
- объектов действительно очень много;
- они заметно расходуют память;
- существенную часть их состояния можно безопасно сделать общей;
- число вариантов внутреннего состояния намного меньше числа контекстов.
Плюсы¶
- Существенно снижает расход памяти при большом числе однотипных объектов.
- Централизует создание и повторное использование общего состояния.
Минусы¶
- Усложняет модель разделением состояния и передачей контекста в методы.
- Может увеличить вычислительные затраты на поиск легковеса и восстановление внешнего состояния.
- Изменяемый легковес опасен: изменение затронет сразу все использующие его контексты.
Отличие от кеша и Singleton¶
Фабрика Flyweight действительно использует кеш, но цель паттерна - разделить внутреннее состояние между огромным числом логических объектов. Обычный кеш чаще ускоряет получение данных. Singleton гарантирует единственный экземпляр одного класса, а Flyweight допускает множество экземпляров - по одному на каждый вариант внутреннего состояния.
Пример в .NET¶
- Интернирование строк (
string.Intern) позволяет одинаковым строковым значениям разделять один экземпляр, хотя ручное интернирование следует применять осторожно из-за времени жизни intern pool. - Пулы и кеши метаданных могут использовать ту же идею разделения тяжёлого неизменяемого состояния, но не каждый пул является Flyweight.
Источник для сверки структуры: Refactoring.Guru - Flyweight.