Давайте рассмотрим паттерн проектирования Одиночка C#, для чего он нужен и какие проблемы он решает. Где можно применять шаблон Singleton C#, а где это будет излишним.
Идея паттерна проектирования Одиночка
Паттерн (шаблон) проектирования — это продуманный способ построения исходного кода программы для решения часто возникающих в повседневном программировании проблем проектирования. Иными словами, это уже придуманное решения, для типичной задачи. При этом паттерн не готовое решение, а просто алгоритм действий, который должен привести к желаемому результату. Давайте рассмотрим один из наиболее простых паттернов — Singleton (Одиночка).
Существует три вида паттернов проектирования:
- Порождающие паттерны позволяют возможность выполнять инициализацию объектов наиболее удобным и оптимальным способом.
- Структурные паттерны описывают взаимоотношения между различными классами или объектами, позволяя им совместно реализовывать поставленную задачу.
- Поведенческие паттерны позволяют грамотно организовать связь между сущностями для оптимизации и упрощения их взаимодействия.
Singleton (Одиночка) — это порождающий паттерн, гарантирующий, что для класса будет создан только один единственный экземпляр. То есть, при обращении к классу будет создан уникальный в рамках программы объект, защищенный от возможности создания подобных себе объектов, предоставляющий глобальную точку доступа к этому экземпляру. При этом объект будет создаваться только при необходимости, когда к нему будет выполняться обращение.
Архитектура паттерна Singleton
На рисунке представлена схема структуры класса.
- Singleton — уникальный статический экземпляр класса
- getInstance() — метод получения экземпляра класса. Если экземпляр еще не создан, то создает новый.
Логика работы паттерна Singleton (Одиночка)
- Добавим в класс закрытое статическое поле, в котором будет находиться основной уникальный экземпляр класса
- Создадим статичный метод, используемый для получения уникального экземпляра класса
- Реализуем создание уникального экземпляра при первом обращении к нему (так называемая «ленивая инициализация»)
- Добавим закрытий конструктор класса
- Вызовем создание экземпляра класса с помощью статичного метода
Реализация паттерна проектирования Singleton (Одиночка) на языке C#
Singleton.cs
using System; namespace Patterns.Singleton { /// <summary> /// Класс, реализующий паттерн Одиночка. /// </summary> /// <remarks> /// Порождающий паттерн, гарантирующий, что для класса будет создан только один единственный экземпляр. /// </remarks> public class Singleton { /// <summary> /// Объект синхронизации, необходим для безопасности при многопоточном использовании. /// </summary> private static object _sync = new object(); /// <summary> /// Основной объект, в котором будет храниться уникальный экземпляр класса. /// </summary> private static volatile Singleton _instance; /// <summary> /// Какие-либо хранимые данные. /// </summary> private string _data; /// <summary> /// Данные, используемые в классе. /// </summary> public string Data => _data; /// <summary> /// Защищенный конструктор для инициализации единственного экземпляра класса. /// </summary> /// <param name="data">Данные, используемые в классе.</param> private Singleton(string data) { _data = data; } /// <summary> /// Получить экземпляр класса. /// </summary> /// <param name="data">Инициализирующие данные класса.</param> /// <returns>Уникальный экземпляр класса.</returns> public static Singleton GetInstance(string data) { if(string.IsNullOrEmpty(data)) { throw new ArgumentNullException(nameof(data)); } // Если экземпляр еще не инициализирован - выполняем инициализацию. // Иначе возвращаем имеющийся экземпляр. if (_instance == null) { lock (_sync) // Используется чтобы избежать одновременного доступа критической секции из разных потоков. { if (_instance == null) { _instance = new Singleton(data); } } } return _instance; } /// <summary> /// Приведение объекта к строке. /// </summary> /// <returns>Данные класса в строковом формате.</returns> public override string ToString() { return Data; } } }
Вызов класса. Попытаемся создать несколько экземпляров класса одиночки.
Program.cs
static void Main(string[] args) { var singleton = Singleton.GetInstance("Привет, мир!"); var singleton2 = Singleton.GetInstance("Здравствуй, космос!"); Console.WriteLine(singleton2.Data); Console.ReadLine(); }
В результате получим следующий результат:
Как мы видим, при попытке создания нескольких экземпляров класса, мы получаем один единственный уникальный экземпляр класса, с единой точкой входа и реализующий механизм поздней инициализации. Таким образом, мы полностью добились желаемого результата. Исходный код программы доступен по ссылке в репозитории https://github.com/shwanoff/Singleton
Советую также изучить статью Паттерн проектирования Стратегия (Strategy) на языке C#. А еще подписывайтесь на группу ВКонтакте, Telegram и YouTube-канал. Там еще больше полезного и интересного для программистов.