Autumn SALE
Легковес

Легковес на C#

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

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

Сложность:

Популярность:

Применимость: Весь смысл использования Легковеса — в экономии памяти. Поэтому, если в приложении нет такой проблемы, то вы вряд ли найдёте там примеры Легковеса.

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

Концептуальный пример

Этот пример показывает структуру паттерна Легковес, а именно — из каких классов он состоит, какие роли эти классы выполняют и как они взаимодействуют друг с другом.

Program.cs: Пример структуры паттерна

using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; // Используем библиотеку Json.NET, загрузить можно через NuGet Package Manager namespace RefactoringGuru.DesignPatterns.Flyweight.Conceptual { // Легковес хранит общую часть состояния (также называемую внутренним // состоянием), которая принадлежит нескольким реальным бизнес-объектам. // Легковес принимает оставшуюся часть состояния (внешнее состояние, // уникальное для каждого объекта) через его параметры метода. public class Flyweight { private Car _sharedState; public Flyweight(Car car) { this._sharedState = car; } public void Operation(Car uniqueState) { string s = JsonSerializer.Serialize(this._sharedState); string u = JsonSerializer.Serialize(uniqueState); Console.WriteLine($"Flyweight: Displaying shared {s} and unique {u} state."); } } // Фабрика Легковесов создает объекты-Легковесы и управляет ими. Она // обеспечивает правильное разделение легковесов. Когда клиент запрашивает // легковес, фабрика либо возвращает существующий экземпляр, либо создает // новый, если он ещё не существует. public class FlyweightFactory { private List<Tuple<Flyweight, string>> flyweights = new List<Tuple<Flyweight, string>>(); public FlyweightFactory(params Car[] args) { foreach (var elem in args) { flyweights.Add(new Tuple<Flyweight, string>(new Flyweight(elem), this.getKey(elem))); } } // Возвращает хеш строки Легковеса для данного состояния. public string getKey(Car key) { List<string> elements = new List<string>(); elements.Add(key.Model); elements.Add(key.Color); elements.Add(key.Company); if (key.Owner != null && key.Number != null) { elements.Add(key.Number); elements.Add(key.Owner); } elements.Sort(); return string.Join("_", elements); } // Возвращает существующий Легковес с заданным состоянием или создает // новый. public Flyweight GetFlyweight(Car sharedState) { string key = this.getKey(sharedState); if (flyweights.Where(t => t.Item2 == key).Count() == 0) { Console.WriteLine("FlyweightFactory: Can't find a flyweight, creating new one."); this.flyweights.Add(new Tuple<Flyweight, string>(new Flyweight(sharedState), key)); } else { Console.WriteLine("FlyweightFactory: Reusing existing flyweight."); } return this.flyweights.Where(t => t.Item2 == key).FirstOrDefault().Item1; } public void listFlyweights() { var count = flyweights.Count; Console.WriteLine($"\nFlyweightFactory: I have {count} flyweights:"); foreach (var flyweight in flyweights) { Console.WriteLine(flyweight.Item2); } } } public class Car { public string Owner { get; set; } public string Number { get; set; } public string Company { get; set; } public string Model { get; set; } public string Color { get; set; } } class Program { static void Main(string[] args) { // Клиентский код обычно создает кучу предварительно заполненных // легковесов на этапе инициализации приложения. var factory = new FlyweightFactory( new Car { Company = "Chevrolet", Model = "Camaro2018", Color = "pink" }, new Car { Company = "Mercedes Benz", Model = "C300", Color = "black" }, new Car { Company = "Mercedes Benz", Model = "C500", Color = "red" }, new Car { Company = "BMW", Model = "M5", Color = "red" }, new Car { Company = "BMW", Model = "X6", Color = "white" } ); factory.listFlyweights(); addCarToPoliceDatabase(factory, new Car { Number = "CL234IR", Owner = "James Doe", Company = "BMW", Model = "M5", Color = "red" }); addCarToPoliceDatabase(factory, new Car { Number = "CL234IR", Owner = "James Doe", Company = "BMW", Model = "X1", Color = "red" }); factory.listFlyweights(); } public static void addCarToPoliceDatabase(FlyweightFactory factory, Car car) { Console.WriteLine("\nClient: Adding a car to database."); var flyweight = factory.GetFlyweight(new Car { Color = car.Color, Model = car.Model, Company = car.Company }); // Клиентский код либо сохраняет, либо вычисляет внешнее состояние и // передает его методам легковеса. flyweight.Operation(car); } } } 

Output.txt: Результат выполнения

FlyweightFactory: I have 5 flyweights: Camaro2018_Chevrolet_pink black_C300_Mercedes Benz C500_Mercedes Benz_red BMW_M5_red BMW_white_X6 Client: Adding a car to database. FlyweightFactory: Reusing existing flyweight. Flyweight: Displaying shared {"Owner":null,"Number":null,"Company":"BMW","Model":"M5","Color":"red"} and unique {"Owner":"James Doe","Number":"CL234IR","Company":"BMW","Model":"M5","Color":"red"} state. Client: Adding a car to database. FlyweightFactory: Can't find a flyweight, creating new one. Flyweight: Displaying shared {"Owner":null,"Number":null,"Company":"BMW","Model":"X1","Color":"red"} and unique {"Owner":"James Doe","Number":"CL234IR","Company":"BMW","Model":"X1","Color":"red"} state. FlyweightFactory: I have 6 flyweights: Camaro2018_Chevrolet_pink black_C300_Mercedes Benz C500_Mercedes Benz_red BMW_M5_red BMW_white_X6 BMW_red_X1 

Легковес на других языках программирования

Легковес на C++ Легковес на Go Легковес на Java Легковес на PHP Легковес на Python Легковес на Ruby Легковес на Rust Легковес на Swift Легковес на TypeScript