Давайте представим, что у нас есть приложение с котиками. Каждый котик имеет имя, возраст, породу и любимую игрушку. В обычном подходе мы бы создали отдельный объект для каждого котика со всеми этими характеристиками. Но что если у многих котиков одна и та же любимая игрушка? Правда нужно создавать новую игрушку каждый раз, даже если у другого котика она такая же? Здесь на помощь приходит паттерн Легковес.
Пример кода: https://github.com/Ladgertha/patterns/commit/fd784b8a7ff2811de2343b237a073967cfc15550
У нас есть котик:
Мы вынесли игрушку в отдельный класс, потому что у многих котиков может быть одинаковая игрушка.
И сделали фабрику для игрушек:
Теперь вместо того чтобы создавать новую игрушку для каждого котика, мы используем ToyFactory, которая возвращает существующую игрушку, если она уже была создана. Таким образом экономится память.
Как видите, сам паттерн достаточно легкий. Но у него тоже есть несколько интересных аспектов, которые могут быть полезными:
- Кэширование: это одна из ключевых особенностей паттерна — использование кэширования для уменьшения количества создаваемых объектов.
- Иммутабельность: легковесные объекты обычно делаются неизменяемыми, чтобы после их создания их состояние не изменялось. Это упрощает управление ресурсами и обеспечивает безопасность при многопоточном доступе.
- Применение в графических интерфейсах: паттерн часто используется в UI. Это позволяет значительно уменьшить расход памяти. Как пример: в какой-нибудь игре, где множество оружия, мы можем использовать паттерн, а не создавать каждый раз новый объект оружия.
- Разделение состояния на внутреннее и внешнее: паттерн разделяет состояние объекта на "внутреннее" (неизменяемое, общее для всех объектов) и "внешнее" (изменяемое, уникальное для каждого объекта). Внутреннее состояние и является тем, что кэшируется и совместно используется (наша игрушка у кота — внутреннее состояние, а имя котика — внешнее).
- В Android уже есть примеры использования паттерна Легковес. Например, метод valueOf() в Integer и Boolean, использует предварительно созданные объекты, чтобы избежать ненужного создания новых экземпляров.
- Оптимизация производительности: в ситуациях, когда производительность критична, таких как рендеринг сложных сцен в играх, Легковес может использоваться для уменьшения затрат на отрисовку и обработку большого количества похожих объектов. Выше я как раз приводила пример с оружием в игре.
- Совместное использование объектов: цель паттерна Легковес — уменьшить количество объектов, создаваемых и хранящихся в памяти. Для этого он использует совместное использование объектов там, где это возможно. Например, наши котики совместно используют мячик.
Преимущества:
- Экономия памяти: повторное использование уже существующих объектов снижает потребление памяти.
- Быстродействие: уменьшение общего количества объектов улучшает производительность приложения
Недостатки:
- Сложность кода: введение паттерна увеличивает сложность кода. Но замечу, что не сильно усложняет. Видели мы паттерны, которые гораздо сложнее и состоят из десятка классов.
- Компромисс между памятью и временем выполнения: иногда экономия памяти может увеличить время доступа к данным.
Где использовать?
- В приложениях, где нужно обрабатывать большое количество похожих объектов с общими характеристиками.
- В случаях, когда экономия памяти может значительно повлиять на производительность, например, в играх или графических приложениях.
Дубль статей в телеграмме — https://t.me/android_junior
Мои заметки в телеграмме — https://t.me/android_junior_notes
P.S. сделано с помощью ChatGPT и Midjourney. :)