В чем разница между шаблоном Singleton и статическим классом в Java? [duplicate]

На этот вопрос уже есть ответ:

Чем синглтон отличается от класса, заполненного только статическими полями?

36
задан cesar 20 August 2010 в 15:05
поделиться

11 ответов

Почти каждый раз, когда я пишу статический класс, я в итоге жалею, что не реализовал его как нестатический. Рассмотрим:

  • Нестатический класс может быть расширен. Полиморфизм может избавить от множества повторений.
  • Нестатический класс может реализовать интерфейс, что может пригодиться, когда вы хотите отделить реализацию от API.

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

Однако шаблон синглтона - это лишь полшага от статических классов. Вы как бы получаете эти преимущества, но если вы обращаетесь к ним непосредственно внутри других классов через `ClassName.Instance', вы создаете препятствие для доступа к этим преимуществам. Как указал ph0enix, гораздо лучше использовать паттерн инъекции зависимостей. Таким образом, DI-фреймворку можно сообщить, что конкретный класс является (или не является) синглтоном. Вы получаете все преимущества мокинга, модульного тестирования, полиморфизма и гораздо большую гибкость.

37
ответ дан 27 November 2019 в 05:49
поделиться

Подведем итоги :)

Существенное различие: форма существования синглтона - это объект , статики нет. Это привело к следующему:

  • Синглтон может быть расширен. Статического нет.
  • Создание синглтона может быть небезопасным для потоков, если оно не реализовано должным образом. Статического нет.
  • Синглтон можно передавать как объект. Статического нет.
  • Синглтон может быть обработан сборщиком мусора. Статического нет.
  • Синглтон лучше статического класса!
  • Здесь больше, но я еще не понял :)

И последнее, но не менее важное: всякий раз, когда вы собираетесь реализовать синглтон, пожалуйста, подумайте о том, чтобы изменить свою идею, чтобы не использовать этот объект Бога (поверьте мне, вы будете склонны чтобы поместить все "интересные" вещи в этот класс) и использовать вместо него обычный класс с именем "Context" или что-то в этом роде.

12
ответ дан 27 November 2019 в 05:49
поделиться

Синглтон можно инициализировать лениво, например.

5
ответ дан 27 November 2019 в 05:49
поделиться

ПРИМЕЧАНИЕ: Примеры приведены на 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
   }
}

Это не значит, что статические классы ВСЕГДА плохи, просто это не лучший кандидат для таких вещей, как файловые системы, соединения с базами данных и другие зависимости нижнего уровня.

0
ответ дан 27 November 2019 в 05:49
поделиться

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

2
ответ дан 27 November 2019 в 05:49
поделиться

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

class NoSingleton {
  static {
    //initialize foo with something complex that can't be done otherwise
  }
  static private foo;
}

Затем это будет выполняться во время загрузки класса, что, вероятно, не то, что вам нужно. У вас будет больше контроля над всей этой шебангой, если вы реализуете ее как синглтон. Однако я думаю, что использование синглтонов в любом случае - не лучшая идея.

1
ответ дан 27 November 2019 в 05:49
поделиться

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

Хотя класс имеет только статические методы, на самом деле нет необходимости в создании экземпляра (по этой причине большинство людей / фреймворков делают такие классы Util абстрактными). Вы просто вызовете методы класса напрямую.

2
ответ дан 27 November 2019 в 05:49
поделиться

Разница заключается в том, что язык не зависит. Singleton по определению: «Убедитесь, что класс имеет только один экземпляр и предоставляет глобальную точку доступа к нему. » Класс, заполненный только статическими полями, не то же самое, что синглтон, но, возможно, в вашем сценарии использования они предоставляют ту же функциональность. Но, как сказал JRL, ленивое посвящение — это одно отличие.

3
ответ дан 27 November 2019 в 05:49
поделиться

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

Вариантом может быть небольшой пул этих объектов, что было бы невозможно, если бы все методы были статическими.

2
ответ дан 27 November 2019 в 05:49
поделиться

Singleton Class : Синглтон класс - это класс, только один экземпляр которого может существовать в одном загрузчике классов.

Helper Class (класс, имеющий только статические поля/методы) : Экземпляров этого класса не существует. Только поля и методы могут быть доступны напрямую как константы или вспомогательные методы.

Эти несколько строк из этого блога хорошо описывают это:

Во-первых, паттерн Singleton является очень полезен, если вы хотите создать один экземпляр класса. Для моего вспомогательного класса мы не хотим создавать какие-либо экземпляры класса. Причина, по которой вы не должны использовать класс Singleton, потому что для этого класса-помощника мы не используем никаких переменные. Класс синглтон был бы полезным, если бы он содержал набор переменных, которые нам нужны только для одного набора и методы использовали бы эти переменные, но в нашем вспомогательном классе мы не используем никаких переменных, кроме (которые мы делаем конечными). По этой причине я не думаю, что мы хотим иметь единичный экземпляр, потому что мы не хотим никаких переменных и не хотим, чтобы не хотим, чтобы кто-то инстанцировал этот класс. Поэтому, если вы не хотите, чтобы кто-то инстанцировать класс, что обычно, если у вас есть какой-то вспомогательный/полезный класс, тогда я использую то. Я называю статический класс, класс с закрытым конструктором и только состоит из статических методов без каких-либо каких-либо переменных.

0
ответ дан 27 November 2019 в 05:49
поделиться

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

0
ответ дан 27 November 2019 в 05:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: