Что такое Flyweight и как он экономит память?
Структурные паттерны
Flyweight делит состояние объекта на внутреннее (общее, неизменяемое) и внешнее (уникальное) и хранит общую часть в одном экземпляре на все объекты, которые её используют.
Как экономит
- Карта с 1 000 000 деревьев: если каждое хранит свою текстуру (~1 КБ) и координаты, выходит ~1 ГБ.
- Выносим текстуру, цвет и название вида в
TreeType. Видов 10 — значит, 10 тяжёлых объектов, а дерево хранит толькоx,yи ссылку: порядок десятков мегабайт. - Фабрика кэширует разделяемые объекты по ключу в
Map<string, TreeType>и никогда не создаёт дубль.
Условия применимости
- Объектов действительно очень много, и у них большая повторяющаяся часть.
- Внутреннее состояние неизменяемо, иначе правка одного «дерева» заденет все.
- Внешнее состояние передаётся в методы (
draw(ctx, x, y)) или хранится в контейнере-владельце.
Где встречается
- Интернирование строк в JVM и V8, кэш
Integer.valueOfдля диапазона −128…127. - Глифы в текстовых редакторах: символ «а» с данными шрифта — один объект, позиции хранятся отдельно.
- Скрытые классы V8: объекты с одинаковой формой делят описание раскладки свойств.
Цена
Код усложняется разделением состояния, а поиск во фабрике и передача внешних данных тратят CPU — выигрыш есть только при реальном давлении на память.
Коротко для собеседования
Flyweight выносит повторяющиеся неизменяемые данные в общие объекты из фабрики-кэша, а уникальные поля хранит отдельно или передаёт в методы. Имеет смысл только при миллионах похожих объектов и реальном давлении на память, иначе лишь усложняет код.