Реализация структурного шаблона проектирования

Шаблон Flyweight экономит память и снижает затраты на создание подобных объектов, использующих одни и те же неизменяемые свойства.

Когда я должен использовать наилегчайший вес?

Приспособленцы — отличное решение, когда вы повторяете один и тот же неизменяемый набор свойств в нескольких классах, особенно если создание объектов обходится дорого.

Когда мне следует избегать использования наилегчайшего веса?

Не используйте легковесы, когда вам нужно более одного объекта внутреннего состояния. Вместо этого используйте шаблоны Singleton или Factory для взаимодействия с экземпляром общего состояния.

«При создании легковесов будьте осторожны с тем, насколько велика ваша память о легковесах. Если вы храните несколько легковесов, вы минимизируете использование памяти для одного и того же объекта, но вы все равно можете использовать слишком много памяти в хранилище легковесов.

Чтобы смягчить это, установите ограничения на объем используемой памяти или зарегистрируйтесь для предупреждений о памяти и реагируйте, удаляя из памяти некоторые легковесы. Вы можете использовать кэш LRU (наименее недавно использованный) для обработки этого».

Рэй Вендерлих

Основной дизайн

На высоком уровне дизайн имеет как внутреннее, так и внешнее состояние. Используйте ссылочный тип для внутреннего состояния.

Вы не можете использовать Struct или Enum, потому что они будут автоматически скопированы по ссылке, что приведет к проблеме, которую пытается решить Приспособленец. В этом случае внешнее состояние будет содержать изменяемые свойства.

Пример

UIColor использует шаблон Flyweight, так как цвета не будут изменены.

Console Output:
Same instance!

Используя ===, мы можем сравнить, что обе стороны являются одним и тем же экземпляром в памяти, а не просто копиями друг друга. Итак, мы доказали, что redColorOne и redColorTwo указывают на один и тот же адрес в памяти.

Как рефакторить существующий код

Давайте применим паттерн Flyweight на практике. Создайте новую игровую площадку в Xcode и определите класс с именем Tesla. Мы начнем с этого класса, а затем проведем рефакторинг для использования шаблона Flyweight.

Первый шаг — отделение неизменяемых частей объекта от изменяемого набора свойств.

Части, которые никогда не изменятся, могут храниться в Приспособленце, а клиент может управлять изменяемыми свойствами, передавая их Приспособленцу при необходимости.

Нам также нужно где-то хранить инициализированные легковесные объекты. HashMap использует пару ключ/значение (KVP) и значительно более эффективен, чем массивы, при доступе к базовому значению в памяти, поэтому давайте для этого примера воспользуемся HashMap.

В качестве бонуса мы можем использовать identifier в качестве ключа, который гораздо проще поддерживать. Добавьте новую частную коллекцию с именем gigaFactory.

В примере с UIColor UIColor.red была статической функцией. При назначении свойств рекомендуется опираться на вывод типа, поэтому добавьте три статических свойства типа: Tesla. (Мы еще не написали метод build(_:). Но не волнуйтесь, это будет дальше)

Последним шагом является управление доступом к легковесам. Давайте сделаем этот метод build(_:). Он проверит наш gigafactory, чтобы убедиться, что запрошенный автомобиль уже существует.

Если это так, верните его, в противном случае создайте новый экземпляр и верните его после обновления коллекции, включив в нее новое транспортное средство.

Создайте и запустите приложение. Каждый Tesla загружается только один раз и не может быть зарегистрирован более одного раза.

Вы успешно сократили время обработки и загрузки в своем приложении!

Console Output:
true   // 1
false  // 2
false  // 3
true   // 4

Надеюсь, вы почувствуете себя более уверенно, поняв структурный паттерн наилегчайшего веса.

Помнить

  • Шаблон Flyweight минимизирует использование памяти и обработку.
  • Этот шаблон имеет объекты, называемые приспособленцами, и статический метод для их возврата. Это вариант шаблона Singleton.
  • При создании приспособлений будьте осторожны с объемом памяти. Если вы храните несколько приспособлений, все равно можно использовать слишком много памяти в хранилище приспособленцев.
  • Примеры легковесов включают кэширование таких объектов, как изображения, или сохранение пула объектов в памяти для быстрого доступа.
  • Легковесы очень распространены в UIKit. UIColor, UIFont и UITableViewCell — все это примеры классов с легковесами.