В чем разница патерна Singleton и модификатора static в C#

Насколько я правильно понял static хранит состояние всего класса. С ним же можно создавать классы и методы. Тогда вопрос зачем нужен Singleton и в каких задачах его используют?


Ответы (1 шт):

Автор решения: InterceptorTSK

В очень простом случае, синглтон - это по какой то причине [нужной причине] - единственный экземпляр "чего то".

Например, у вас есть класс окна, и он должен быть один, потому что вы так задумали. Но никто не запрещает в коде/кодом создать ещё несколько таких же окон, и запустить их. Тогда будет много экземпляров окон, и что делать? Некоторые экземпляры "чего то" - единственные, а синглтон обеспечивает в некотором смысле "защиту" от повторного создания экземпляра, например второго-третьего окна. Запрещает/противодействует созданию нескольких экземпляров "чего то".

Статик здесь совершенно ни при чём. Статические переменные, методы и классы - это детали реализации. Например общепринятых [или не очень] паттернов программирования.

В синглтонах [обычно] действительно объявляют тот самый единственный экземпляр - статическим. А почему? Если не вдаваться в подробности, то всякое статическое в тех же классах - поля/методы инициализируются и исполняются прежде всего. Грубо говоря всякое статическое будет исполнено, а уже затем - не статическое.

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

public class Window
{
    // Это статическое поле, при первом обращении
    // к этому классу [на самом деле типу] -
    // это поле исполнится прежде всего.
    // Переменной Singleton будет назначен
    // новосозданный экземпляр объекта Window.

    public static readonly Window Singleton = new Window();

    // Конструктор не запрещает создавать ещё
    // экземпляры этого объекта.

    public Window() // [1 вариант]
    {
    }

    // Можно закрыть конструктор как private
    // тогда внешний код не сможет создать экземпляр
    // объекта Window, извне.

    private Window() // [2 вариант]
    {
    }
}

public static class Program
{
    public static void Main()
    {
        // Обращаемся к статическому полю
        // класса окошка, а окошко создано
        // самим классом Window.

        Window windowOne = Window.Singleton;

        // Можно создать ещё окошко, но если
        // конструктор публичный, а если
        // конструктор закрыт, то второе-третье
        // окошко создать нельзя.

        // Если конструктор public, создаём второе окно.

        Window windowTwo = new Window();

        // Если конструктор private, ошибка компиляции
        // Закрытый конструктор не позволяет
        // создавать окна ещё и ещё.

        Window windowThree = new Window(); // Compile error
    }
}

Статические классы, поля, методы - это детали ООП, способ организации кода, а синглтон - это логическая абстрактная единственность. Можно собрать синглтон иначе, например [почти] без статических штуковин.

public class Window
{
    // Это статическое поле, при первом обращении
    // к этому классу [на самом деле типу] -
    // это поле исполнится прежде всего.

    private static readonly bool _isCreated = false;

    // Конструктор не запрещает создавать ещё
    // экземпляры этого объекта, но флаг запрещает
    // создавать более чем одно окно,
    // и проверка этого флага _isCreated.

    public Window()
    {
        // Проверяем флаг, изначально флаг=false

        if (_isCreated)
            throw new System.Exception("Окно уже создано.");

        // Ставим флаг в true, последующие попытки
        // создать окно будут выкидывать ошибку.

        _isCreated = true;
    }
}

public static class Program
{
    public static void Main()
    {
        // Создаём окошко.

        Window windowOne = new Window();

        // Можно создать ещё окошко, но внутренний
        // флаг конструктора окна проверяет единственность
        // и будет выкинута ошибка, второе окно не получится.

        Window windowTwo = new Window(); // Runtime error
    }
}

Способов синглтонов превеликое количество, это детали реализации, а реализации разные, потому что нужны разные реализации. И единственных паттернов - не существует. Паттерны выбирают осмысленно, в тех или иных случаях подбирают паттерны или кодируют что то своё.

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

public class Window
{
    /// <summary>Это синглтон, создавайте один экземпляр этого класса.</summary>

    public Window()
    {
    }
}

public static class Program
{
    public static void Main()
    {
        // Создаём окошко.

        Window windowOne = new Window();

        // Можно создать ещё окошко, но если читаете
        // документацию, то второе окошко не создадите,
        // создание второго окна запрещает документация.

        Window windowTwo = new Window(); // Documentation error
    }
}
→ Ссылка