Порівняння паттернів Singleton та Multion
Порівняння паттернів Singleton та Multion

Паттерн дизайну Multiton та Singleton відносять до групи твірних паттернів. Одразу зауважимо, що Multion є розширенням паттерну Singleton. Вони використовуються для обмеження створення декількох об’єктів одного класу.

Паттерн Singleton

Паттерн Singleton обмежує створення екземпляру класу. Він гарантує, що лише єдиний раз об’єкт класу буде створено, а далі будуть використані посилання на вже створений об’єкт.

Singleton дуже корисний, коли необхідна єдина глобальна точка доступу до обмеженого ресурсу. Це більш доречно, ніж використовувати глобальні змінні, копіювати їх значення і перейматись тим, що дублікати не встигатимуть за оригіналом.

Прикладом використання Singleton є під’єднання до застарілих джерел даних, які не підтримують більше одного читача одночасно. Коли ми використовуємо лише один об’єкт, то лише одне підключення може бути доступне одночасно.

Також Singleton зручно використовувати, коли потрібно постійно створювати новий екземпляр класу, наприклад при логуванні.

Розглянемо реалізацію паттерну:

Зліва на малюнку зображено діаграму класу, який реалізує паттерн Singleton. На цій діаграмі єдиний відкритий (public) статичний  метод це GetObj(). Цей метод і повертає посилання на об’єкт, яке знаходиться у закритому (private) полі _obj, або створює екземпляр класу, використовуючи закритий конструктор, якщо метод викликано вперше. Зверніть увагу, що створити об’єкт класу поза межами класу неможливо, бо у класі відсутній відкритий (public) конструктор. Цей клас також sealed (не може бути батьківським), щоб унеможливити створення відкритого конструктора в нащадках.

Розглянемо код реалізації паттерну:

public sealed class Example
{
    private static Example _obj;
    private static object _lock = new object();
 
    private Example() { }
 
    public static Example GetObj()
    {
        lock (_lock)
        {
            if (_obj == null) _obj = new Example();
        }
 
        return _obj;
    }
}

І ще важливий момент, ми пропустили об’єкт _lock, який використовує блокування у методі GetObj(). Так як C# програми можуть виконуватися в кількох потоках, то для того щоб попередити ситуацію коли два потоки можуть використати Singleton одночасно і створити два різні об’єкти класу (що порушує принцип паттерну) використовується допоміжний об’єкт блокування, що унеможливлює такий випадок.

Паттерн Multiton

Multiton гарантує, що  обмежена кількість екземплярів класу може існувати при присвоєнні кожному екземпляру унікального ключа, але лише один об’єкт може буде створений для кожного із цих ключів. Він дуже схожий по реалізації і принципу роботи на Singleton: викликається статичний метод, якому передається ключ і він повертає посилання або створює екземпляр класу. Якщо ключ існує, то повертається посилання, якщо ключ новий, то створюється новий об’єкт класу. По суті, Multiton забезпечує функціонування групи Singleton’ів.

Розглянемо, як приклад камери безпеки. Кожна камера має свій контролер. Кількість камер може змінюватися, тому використовувати Singleton тут недоцільно. Кожен контролер буде представлений окремим ключем у Multiton. Таким чином неможлива буде ситуація, два контролери з’єднані з тими ж камерами.

Справа на зображенні зображена діаграма класу Sample, що реалізує Multiton. Єдиним відкритим (public) методом є GetSample(). Цей метод повертає посилання на екземпляр класу, який відповідає заданому ключу, а якщо ключ новий то створює об’єкт класу. Конструктор класу закритий (private), що не дозволяє створення об’єкта поза межами класу. Клас також sealed, що унеможливлює його успадкування, так як наслідування може розірвати принцип паттерну.

Розглянемо код реалізації паттерну (C#):

public sealed class Sample
{
    static Dictionary<string, Sample> _instances = new Dictionary<string, Sample>();
    static object _lock = new object();
 
    private Sample() { }
 
    public static Sample GetSample(string key)
    {
        lock (_lock)
        {
            if (!_instances.ContainsKey(key)) _instances.Add(key, new Sample());
        }
        return _instances[key];
    }
}

Зверніть увагу, що також реалізовано блокування, для уникнення проблем при виконанні програми в декількох потоках.

Напишіть відгук

Ваша пошт@ не публікуватиметься. Обов’язкові поля позначені *