На этот вопрос уже есть ответ:
Чем синглтон отличается от класса, заполненного только статическими полями?
Почти каждый раз, когда я пишу статический класс, я в итоге жалею, что не реализовал его как нестатический. Рассмотрим:
Из-за этих двух моментов нестатические классы позволяют писать более надежные модульные тесты для элементов, которые зависят от них, помимо всего прочего.
Однако шаблон синглтона - это лишь полшага от статических классов. Вы как бы получаете эти преимущества, но если вы обращаетесь к ним непосредственно внутри других классов через `ClassName.Instance', вы создаете препятствие для доступа к этим преимуществам. Как указал ph0enix, гораздо лучше использовать паттерн инъекции зависимостей. Таким образом, DI-фреймворку можно сообщить, что конкретный класс является (или не является) синглтоном. Вы получаете все преимущества мокинга, модульного тестирования, полиморфизма и гораздо большую гибкость.
Подведем итоги :)
Существенное различие: форма существования синглтона - это объект , статики нет. Это привело к следующему:
И последнее, но не менее важное: всякий раз, когда вы собираетесь реализовать синглтон, пожалуйста, подумайте о том, чтобы изменить свою идею, чтобы не использовать этот объект Бога (поверьте мне, вы будете склонны чтобы поместить все "интересные" вещи в этот класс) и использовать вместо него обычный класс с именем "Context" или что-то в этом роде.
ПРИМЕЧАНИЕ: Примеры приведены на C#, поскольку именно с ним я знаком лучше всего, но концепция должна быть применима и к Java.
Не обращая внимания на дебаты о том, когда уместно использовать объекты Singleton, одно основное различие, о котором я знаю, заключается в том, что объект Singleton имеет экземпляр, который можно передавать по кругу.
Если вы используете статический класс, вы жестко привязываете себя к определенной реализации, и нет возможности изменить его поведение во время выполнения.
Плохой дизайн при использовании статического класса:
public class MyClass
{
public void SomeMethod(string filename)
{
if (File.Exists(filename))
// do something
}
}
В качестве альтернативы, вы можете сделать так, чтобы ваш конструктор принимал экземпляр определенного интерфейса. На производстве вы можете использовать синглтонную реализацию этого интерфейса, но в модульных тестах вы можете просто передразнить интерфейс и изменить его поведение в соответствии с вашими потребностями (например, заставить его бросать какое-нибудь непонятное исключение).
public class MyClass
{
private IFileSystem m_fileSystem;
public MyClass(IFileSystem fileSystem)
{
m_fileSystem = fileSystem;
}
public void SomeMethod(string filename)
{
if (m_fileSystem.FileExists(filename))
// do something
}
}
Это не значит, что статические классы ВСЕГДА плохи, просто это не лучший кандидат для таких вещей, как файловые системы, соединения с базами данных и другие зависимости нижнего уровня.
По крайней мере, вы можете более легко заменить его на макет или заглушку для модульного тестирования. Но я не большой поклонник синглтонов именно по той причине, которую вы описываете: это замаскированные глобальные переменные.
Первое, что приходит в голову, это то, что если вы хотите использовать класс только со статическими методами и атрибутами вместо синглтона, вам придется использовать статический инициализатор для правильной инициализации определенных атрибутов. Пример:
class NoSingleton {
static {
//initialize foo with something complex that can't be done otherwise
}
static private foo;
}
Затем это будет выполняться во время загрузки класса, что, вероятно, не то, что вам нужно. У вас будет больше контроля над всей этой шебангой, если вы реализуете ее как синглтон. Однако я думаю, что использование синглтонов в любом случае - не лучшая идея.
Одноэлементный класс будет иметь экземпляр, который обычно один и только один на загрузчик классов. Таким образом, у него могут быть обычные методы (нестатические), и их можно вызывать в этом конкретном экземпляре.
Хотя класс имеет только статические методы, на самом деле нет необходимости в создании экземпляра (по этой причине большинство людей / фреймворков делают такие классы Util абстрактными). Вы просто вызовете методы класса напрямую.
Разница заключается в том, что язык не зависит. Singleton по определению: «Убедитесь, что класс имеет только один экземпляр и предоставляет глобальную точку доступа к нему. » Класс, заполненный только статическими полями, не то же самое, что синглтон, но, возможно, в вашем сценарии использования они предоставляют ту же функциональность. Но, как сказал JRL, ленивое посвящение — это одно отличие.
Синглтон - это класс с одним принудительным экземпляром. Этот класс может иметь состояние (да, я знаю, что статические переменные содержат состояние), не все переменные-члены или методы должны быть статическими.
Вариантом может быть небольшой пул этих объектов, что было бы невозможно, если бы все методы были статическими.
Singleton Class : Синглтон класс - это класс, только один экземпляр которого может существовать в одном загрузчике классов.
Helper Class (класс, имеющий только статические поля/методы) : Экземпляров этого класса не существует. Только поля и методы могут быть доступны напрямую как константы или вспомогательные методы.
Эти несколько строк из этого блога хорошо описывают это:
Во-первых, паттерн Singleton является очень полезен, если вы хотите создать один экземпляр класса. Для моего вспомогательного класса мы не хотим создавать какие-либо экземпляры класса. Причина, по которой вы не должны использовать класс Singleton, потому что для этого класса-помощника мы не используем никаких переменные. Класс синглтон был бы полезным, если бы он содержал набор переменных, которые нам нужны только для одного набора и методы использовали бы эти переменные, но в нашем вспомогательном классе мы не используем никаких переменных, кроме (которые мы делаем конечными). По этой причине я не думаю, что мы хотим иметь единичный экземпляр, потому что мы не хотим никаких переменных и не хотим, чтобы не хотим, чтобы кто-то инстанцировал этот класс. Поэтому, если вы не хотите, чтобы кто-то инстанцировать класс, что обычно, если у вас есть какой-то вспомогательный/полезный класс, тогда я использую то. Я называю статический класс, класс с закрытым конструктором и только состоит из статических методов без каких-либо каких-либо переменных.
Одним из главных преимуществ синглтонов является то, что вы можете реализовывать интерфейсы и наследоваться от других классов. Иногда у вас есть группа синглтонов, которые предоставляют схожую функциональность, и вы хотите реализовать общий интерфейс, но отвечать за разные ресурсы.