Зачем выбирать статический класс по сравнению с одноэлементной реализацией?

Статический Vs. Вопрос Singleton обсуждался много раз в SO.
Тем не менее, все ответы указывали на многие преимущества синглтона.
Мой вопрос: каковы преимущества статического класса над одноэлементным? Почему бы просто не выбрать один раз каждый раз?

Ответ 1

Статический класс - это технический инструмент в вашей коробке - в основном языковая функция.

Синглтон - это архитектурная концепция.

Вы можете использовать статический класс в качестве средства реализации концепции singleton. Или вы можете использовать другой подход.

С статическими классами в С# есть две потенциальные опасности, если вы не будете осторожны.

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

Ответ 2

От MSDN

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

Ключевым моментом является то, что статические классы do not require an instance reference. Также обратите внимание, что статические классы специально включены языком и компилятором.

Одиночные классы - это только классы, закодированные пользователем, реализующие шаблон дизайна Singleton. Цель Singleton - restrict instantiation of an class to a single instance.

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

то есть.

Console.WriteLine('Hello World');

станет

Console c = Console.getInstance();
c.WriteLine('Hello World');

Ответ 3

Я бы сказал, что они оба (вообще) плохие решения. Существует несколько вариантов использования статических классов, прежде всего простых служебных (на ум приходят методы расширения в С# 3.0). Однако с любой степенью сложности проблемы с тестируемостью начинают возникать.

Скажем, класс A зависит от статического класса B. Вы хотите изолировать класс A. Это тяжело.

Итак, вы идете с Singleton. У вас такая же проблема - класс A зависит от singleton B. Вы не можете тестировать класс A в изоляции.

Если класс B имеет другие зависимости (например, попадание в базу данных) или изменен (другие классы могут изменять свое глобальное состояние), проблема усугубляется.

IoC (Inversion of Control) - это одно из решений этой проблемы; они позволяют вам определять Обычные старые классы как имеющие долгую жизнь. В сочетании с насмешливой библиотекой они могут сделать ваш код очень надежным.

Ответ 4

Статические классы намного проще реализовать - я видел много попыток в потокобезопасных синглонах на С#, в которых используются схемы наивной блокировки вместо зависимости от гарантированной однократной инициализации статических полей (необязательно внутри вложенного класса для задержки создания экземпляра).

Кроме того, я думаю, что синглтоны великолепны, если вам нужно передать ссылку на объект, который реализует определенный интерфейс, когда эта "реализация" должна быть singleton, то, что вы не можете делать со статическими классами.

Ответ 5

Одно из соображений, о которых я не вижу, заключается в том, что предпочтение решения, использующего экземпляр класса (singletons или их эквивалент DI), позволяет вам предоставить класс, на котором другие пользователи вашего кода могут определять методы расширения - поскольку методы расширения работают только с нестационарными классами как параметр this. Другими словами, если у вас есть строка, например:

GlobalSettings.SomeMethod();

Тогда синтаксически единственное, к чему можно обратиться через GlobalSettings, - это члены, которые вы предоставляете. Напротив, если GlobalSettings является экземпляром (singleton или иначе), то потребители могут добавлять свои собственные расширения к GlobalSettings, чтобы они не могли сделать иначе:

application.GlobalSettings.CustomSomethingOrOther();

или

GlobalSettings.Instance.CustomSomethingOrOther();