Jump to content

Модель наилегчайшего веса

Скриншот пакета Writer LibreOffice.
Текстовые редакторы, такие как LibreOffice Writer , часто используют шаблон «легкий вес».

В компьютерном программировании шаблон «легковес» проектирования программного обеспечения относится к объекту , который минимизирует использование памяти за счет совместного использования некоторых своих данных с другими аналогичными объектами. Шаблон «Легкий вес» — один из двадцати трёх известных шаблонов проектирования GoF . [1] Эти шаблоны способствуют гибкому объектно-ориентированному проектированию программного обеспечения, которое легче внедрять, изменять, тестировать и повторно использовать.

В других контекстах идея совместного использования структур данных называется хешированием .

Этот термин был впервые придуман, а идея широко исследована Полом Колдером и Марком Линтоном в 1990 году. [2] для эффективной обработки информации о глифах в редакторе документов WYSIWYG . [3] Однако подобные методы уже использовались в других системах еще в 1988 году. [4]

Шаблон «приспособленец» полезен при работе с большим количеством объектов, которые имеют общие простые повторяющиеся элементы, которые использовали бы большой объем памяти, если бы они были встроены индивидуально. Обычно общие данные хранятся во внешних структурах данных и временно передаются объектам, когда они используются.

Классическим примером являются структуры данных, используемые для представления символов в текстовом процессоре . Проще говоря, каждый символ в документе может иметь объект- глиф , содержащий контур шрифта, метрики шрифта и другие данные форматирования. Однако при этом для каждого символа будут использоваться сотни или тысячи байт памяти. Вместо этого каждый символ может иметь ссылку на объект-глиф, общий для каждого экземпляра одного и того же символа в документе. Таким образом, внутри необходимо хранить только позицию каждого символа.

В результате легковесные объекты могут: [5]

  • хранить внутреннее состояние, которое является инвариантным, контекстно-независимым и доступным для совместного использования (например, код символа «A» в заданном наборе символов)
  • предоставить интерфейс для передачи внешнего состояния, которое является вариантом, зависит от контекста и не может быть общим (например, положение символа «A» в текстовом документе)

Клиенты могут повторно использовать Flyweight объекты и при необходимости переходить во внешнее состояние, уменьшая количество физически созданных объектов.

Структура

[ редактировать ]
Пример класса UML и диаграммы последовательности для шаблона проектирования «Приспособленный вес». [6]

На приведенной выше UML диаграмме классов показано:

  • тот Client класс, который использует шаблон легковеса
  • тот FlyweightFactory класс, который создает и разделяет Flyweight объекты
  • тот Flyweight интерфейс , который принимает внешнее состояние и выполняет операцию
  • тот Flyweight1 класс, который реализует Flyweight и сохраняет внутреннее состояние

Диаграмма последовательности показывает следующие взаимодействия во время выполнения :

  1. The Client вызовы объектов getFlyweight(key) на FlyweightFactory, который возвращает Flyweight1 объект.
  2. После звонка operation(extrinsicState) на возвращении Flyweight1 объект, Client снова звонит getFlyweight(key) на FlyweightFactory.
  3. The FlyweightFactory возвращает уже существующий Flyweight1 объект.

Детали реализации

[ редактировать ]

Существует несколько способов реализации шаблона наилегчайшего веса. Одним из примеров является изменчивость: могут ли измениться объекты, хранящие внешнее состояние легковеса.

Неизменяемые объекты легко доступны для совместного использования, но при каждом изменении состояния требуется создавать новые внешние объекты. Напротив, изменяемые объекты могут иметь общее состояние. Изменяемость позволяет лучше повторно использовать объекты за счет кэширования и повторной инициализации старых, неиспользуемых объектов. Совместное использование обычно нецелесообразно, когда состояние сильно варьируется.

Другие основные проблемы включают извлечение (как конечный клиент получает доступ к «легкому весу»), кэширование и параллелизм .

Фабричный фасадом интерфейс для создания или повторного использования легковесных объектов часто является сложной базовой системы. Например, интерфейс фабрики обычно реализуется как синглтон , обеспечивающий глобальный доступ для создания приспособилок.

Вообще говоря, алгоритм поиска начинается с запроса нового объекта через интерфейс фабрики.

Запрос обычно перенаправляется в соответствующий кеш в зависимости от типа объекта. Если запрос выполнен объектом в кэше, он может быть повторно инициализирован и возвращен. В противном случае создается экземпляр нового объекта. Если объект разделен на несколько внешних подкомпонентов, они будут объединены перед возвратом объекта.

Кэширование

[ редактировать ]

Существует два способа кэширования объектов-легковесов: поддерживаемый и необслуживаемый.

Объекты с сильно изменчивым состоянием можно кэшировать с помощью структуры FIFO . Эта структура сохраняет неиспользуемые объекты в кеше без необходимости поиска в кеше.

Напротив, необслуживаемые кеши требуют меньше предварительных затрат: объекты для кешей инициализируются массово во время компиляции или запуска. Как только объекты заполняют кэш, алгоритм извлечения объектов может иметь больше накладных расходов, чем операции push/pop поддерживаемого кэша.

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

Отдельные кэши могут использоваться для каждого уникального подкласса внешнего объекта. Несколько кешей можно оптимизировать отдельно, связывая с каждым кешем уникальный алгоритм поиска. Эту систему кэширования объектов можно инкапсулировать с помощью шаблона цепочки ответственности , который способствует слабой связи между компонентами.

Параллелизм

[ редактировать ]

Особое внимание следует принимать во внимание, когда объекты-легковесы создаются в нескольких потоках. Если список значений конечен и известен заранее, экземпляры легковесов могут быть созданы заранее и извлечены из контейнера в нескольких потоках без каких-либо конфликтов. Если легковесы создаются в нескольких потоках, есть два варианта:

  1. Сделайте создание легковесного экземпляра однопоточным, что приведет к возникновению конфликтов и обеспечению одного экземпляра на каждое значение.
  2. Разрешите параллельным потокам создавать несколько экземпляров-легковесов, тем самым устраняя конфликты и позволяя использовать несколько экземпляров для каждого значения.

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

В этом примере из C# 9 используются записи [7] чтобы создать объект значения, представляющий вкусы кофе:

public record CoffeeFlavours(string flavour);

Пример на С#

[ редактировать ]

В этом примере каждый экземпляр MyObject класс использует Pointer класс для предоставления данных.

// Defines Flyweight object that repeats itself.
public class Flyweight
{
    public string Name { get; set; }
    public string Location { get; set; }
    public string Website { get; set; }
    public byte[] Logo { get; set; }
}

public static class Pointer
{
    public static readonly Flyweight Company = new Flyweight    { "Abc","XYZ","www.example.com"    };
}

public class MyObject
{
    public string Name { get; set; }
    public string Company => Pointer.Company.Name;
}

Пример на С++

[ редактировать ]

C++ Стандартная библиотека шаблонов предоставляет несколько контейнеров, которые позволяют сопоставлять уникальные объекты с ключом. Использование контейнеров помогает еще больше сократить использование памяти, устраняя необходимость создания временных объектов.

#include <iostream>
#include <map>
#include <string>

// Instances of Tenant will be the Flyweights
class Tenant {
public:
    Tenant(const std::string& name = "") : m_name(name) {}

    std::string name() const {
        return m_name;
    }
private:
    std::string m_name;
};

// Registry acts as a factory and cache for Tenant flyweight objects
class Registry {
public:
    Registry() : tenants() {}

    Tenant& findByName(const std::string& name) {
        if (!tenants.contains(name)) {
            tenants[name] = Tenant{name};
        }
        return tenants[name];
    }
private:
    std::map<std::string, Tenant> tenants;
};

// Apartment maps a unique tenant to their room number.
class Apartment {
public:
    Apartment() : m_occupants(), m_registry() {}

    void addOccupant(const std::string& name, int room) {
        m_occupants[room] = &m_registry.findByName(name);
    }

    void tenants() {
        for (const auto &i : m_occupants) {
            const int& room = i.first;
            const auto& tenant = i.second;
            std::cout << tenant->name() << " occupies room " << room << std::endl;
        }
    }
private:
    std::map<int, Tenant*> m_occupants;
    Registry m_registry;
};

int main() {
    Apartment apartment;
    apartment.addOccupant("David", 1);
    apartment.addOccupant("Sarah", 3);
    apartment.addOccupant("George", 2);
    apartment.addOccupant("Lisa", 12);
    apartment.addOccupant("Michael", 10);
    apartment.tenants();

    return 0;
}

Пример на PHP

[ редактировать ]
<?php

class CoffeeFlavour {

    private static array $CACHE = [];

    private function __construct(private string $name) {}

    public static function intern(string $name): self {
        self::$CACHE[$name] ??= new self($name);
        return self::$CACHE[$name];
    }

    public static function flavoursInCache(): int {
        return count(self::$CACHE);
    }

    public function __toString(): string {
        return $this->name;
    }

}

class Order {

    private function __construct(
        private CoffeeFlavour $flavour,
        private int $tableNumber
    ) {}

    public static function create(string $flavourName, int $tableNumber): self {
        $flavour = CoffeeFlavour::intern($flavourName);
        return new self($flavour, $tableNumber);
    }

    public function __toString(): string {
        return "Serving {$this->flavour} to table {$this->tableNumber}";
    }
}

class CoffeeShop {

    private array $orders = [];

    public function takeOrder(string $flavour, int $tableNumber) {
        $this->orders[] = Order::create($flavour, $tableNumber);
    }

    public function service() {
        print(implode(PHP_EOL, $this->orders).PHP_EOL);
    }
}

$shop = new CoffeeShop();
$shop->takeOrder("Cappuccino", 2);
$shop->takeOrder("Frappe", 1);
$shop->takeOrder("Espresso", 1);
$shop->takeOrder("Frappe", 897);
$shop->takeOrder("Cappuccino", 97);
$shop->takeOrder("Frappe", 3);
$shop->takeOrder("Espresso", 3);
$shop->takeOrder("Cappuccino", 3);
$shop->takeOrder("Espresso", 96);
$shop->takeOrder("Frappe", 552);
$shop->takeOrder("Cappuccino", 121);
$shop->takeOrder("Espresso", 121);
$shop->service();
print("CoffeeFlavor objects in cache: ".CoffeeFlavour::flavoursInCache().PHP_EOL);

См. также

[ редактировать ]
  1. ^ Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес (1994). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон Уэсли. стр. 195 и далее . ISBN  978-0-201-63361-0 . {{cite book}}: CS1 maint: несколько имен: список авторов ( ссылка )
  2. ^ Гамма, Эрих ; Ричард Хелм ; Ральф Джонсон ; Джон Влиссидес (1995). Шаблоны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Аддисон-Уэсли . стр. 205–206 . ISBN  978-0-201-63361-0 .
  3. ^ Колдер, Пол Р.; Линтон, Марк А. (октябрь 1990 г.). «Глифы: легковесные объекты для пользовательских интерфейсов». Материалы 3-го ежегодного симпозиума ACM SIGGRAPH по программному обеспечению и технологиям пользовательского интерфейса - UIST '90 . 3-й ежегодный симпозиум ACM SIGGRAPH по программному обеспечению и технологиям пользовательского интерфейса. Сноуберд, Юта, США. стр. 92–101. дои : 10.1145/97924.97935 . ISBN  0-89791-410-4 .
  4. ^ Вайнанд, Эндрю; Гамма, Эрих; Марти, Рудольф (1988). ET++ — объектно-ориентированная платформа приложений на C++ . OOPSLA (Системы, языки и приложения объектно-ориентированного программирования). Сан-Диего, Калифорния, США. стр. 100-1 46–57. CiteSeerX   10.1.1.471.8796 . дои : 10.1145/62083.62089 . ISBN  0-89791-284-5 .
  5. ^ «Реализация шаблонов-легковесов в Java» . Разработчик.com . 28 января 2019 г. Проверено 12 июня 2021 г.
  6. ^ «Шаблон проектирования «Легкий вес» — структура и сотрудничество» . w3sDesign.com . Проверено 12 августа 2017 г.
  7. ^ БиллВагнер. «Записи — справочник по C#» . docs.microsoft.com . Проверено 12 июня 2021 г.
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: d73d770149cfed5bf9ba68a6a55ceafd__1719799200
URL1:https://arc.ask3.ru/arc/aa/d7/fd/d73d770149cfed5bf9ba68a6a55ceafd.html
Заголовок, (Title) документа по адресу, URL1:
Flyweight pattern - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)