Flyweight паттерн

В данной заметке я опишу структурный паттерн “Легковес” или “Приспособленец” (Flyweight)
Данный паттерн относится к группе Структурных шаблонов.

Рассмотрим пример работы паттерна ниже:

Зачем он нужен? Для экономии оперативной памяти. Соглашусь что во времена повсеместного использования Java (которое потребляет cpu и память просто так), это уже и не так уж важно, однако использовать стоит.
На приведенном выше примере выводится только 40 объектов, но если поднять их количество до 120000, то потребление памяти увеличится соответствующе.
Посмотрим на потребление памяти без использования паттерна flyweight в браузере Chromium:

Без использования паттерна потребление памяти составляет ~300 мегабайт.

Теперь добавим в приложение паттерн и посмотрим потребление памяти:

С использованием паттерна потребление памяти составляет ~200 мегабайт, таким образом мы сэкономили 100 мегабайт памяти в тестовом приложении, в серьезных проектах разница может быть гораздо больше.

Как работает?

В приведенном выше примере мы отрисовываем 40 котиков или для наглядности 120 тысяч. Каждый котик загружается в память в виде png изображения, далее в большинстве рендеров оно конвертируется в битовую карту для отрисовки (фактически bmp), делается это для скорости, так как сжатый png очень долго отрисовывается. Без использования паттерна мы загружаем 120 тысяч картинок котиков в оперативную память и рисуем, а вот при использовании паттерна “легковес” мы загружаем в память одного котика и рисуем его 120 тысяч раз с разной позицией и прозрачностью. Вся магия состоит в том, что координаты и прозрачность мы реализуем отдельно от изображения кота, при отрисовке рендер берет всего одного котика и использует объект с координатами и прозрачностью для корректной отрисовки.

Как выглядит в коде?

Ниже приведены примеры для языка Rise

Без использования паттерна:


Картинка кота загружается для каждого объекта в цикле отдельно – catImage.

С использованием паттерна:

Одна картинка кота используется 120 тысячами объектов.

Где используется?

Используется в GUI фреймворках, например у Apple в системе “переиспользования” (reuse) ячеек таблиц UITableViewCell, чем поднимают порог вхождения для новичков которые не знают про этот паттерн. Также повсеместно используется в разработке игр.

Исходный код

https://gitlab.com/demensdeum/patterns/

Источники

https://refactoring.guru/ru/design-patterns/flyweight
http://gameprogrammingpatterns.com/flyweight.html