Зачем использовать синглтон вместо статических методов?

94

Я никогда не находил хороших ответов на эти простые вопросы о вспомогательных / служебных классах:

Зачем мне создавать синглтон (без сохранения состояния) вместо использования статических методов?

Зачем нужен экземпляр объекта, если у объекта нет состояния?

Себастьян Лорбер
источник
возможный дубликат stackoverflow.com/questions/720744/static-class-and-singleton
Майкл Боргвардт
Не думайте, раз уж мы говорим о двух разных языках, поэтому ответ может отличаться, но спасибо за ссылку, в java никогда не слышал термин «моносостояние»
Себастьян Лорбер

Ответы:

79

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

Однако есть несколько угловых случаев, когда может быть полезен даже синглтон без сохранения состояния:

  • В обозримом будущем вы рассчитываете расширить его вместе с государством.
  • Экземпляр объекта вам нужен по какой-то конкретной технической причине.
    Пример: объекты синхронизации для оператора C # lockили Java synchronized.
  • Вам необходимо наследование, т. Е. Вы хотите иметь возможность легко заменить свой синглтон другим, используя тот же интерфейс, но другую реализацию.
    Пример: Toolkit.getDefaultToolkit()метод в Java вернет одноэлемент, точный тип которого зависит от системы.
  • Вам нужно ссылочное равенство для контрольного значения .
    Пример: DBNull.Valueв C #.
Heinzi
источник
27
Я собираюсь использовать +1, хотя ИМХО синглтоны неправильно используются для представления глобальных состояний. Цель синглтона не в том, чтобы сделать объект глобально доступным, а в том, чтобы обеспечить создание экземпляра объекта только один раз. Глобальные объекты - неизбежное зло. Если на самом деле это не требуется, следует стараться не использовать их, поскольку они обычно приводят к сильному связыванию с SomeSingleton.getInstance (). SomeMethod () повсюду. :)
back2dos 04
Это может быть полезно в играх, где вам нужен только один экземпляр рендеринга вместо нескольких экземпляров рендеринга, или с классом сетевого конвейера, где вы настраиваете безопасный канал, в котором одновременно может быть только одно соединение.
Tschallacka
2
С моей точки зрения, наиболее важным моментом является "легко заменить свой синглтон". Rest довольно близок к реализации статического класса.
Теоман Шипахи,
1
Синглтоны - это полезные ненулевые контрольные значения для типов суммы / продукта и т.п. Например, значение None / Nothing в типе Option или значение Empty для типа коллекции. В качестве бонуса вы получаете быстрое тестирование None / Empty, потому что эталонное равенство - это все, что вам нужно.
itsbruce 02
@itsbruce: Ваши примеры не являются одиночными : пустой список - не единственный возможный экземпляр класса List, а значение None - не единственный возможный экземпляр класса Option. Тем не менее, есть пример, когда значение дозорного значения - одиночные, и я взял на себя смелость добавить его к своему ответу. Спасибо за ввод!
Heinzi 02
37

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

Если у вас есть вспомогательный класс служебных функций, который вы используете напрямую, он создает скрытую зависимость; у вас нет контроля над тем, кто может его использовать и где. Внедрение того же вспомогательного класса через экземпляр синглтона без сохранения состояния позволяет вам контролировать, где и как он используется, и заменять его / издеваться над ним / и т. Д., Когда вам нужно.

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

цаман
источник
1
«у вас нет контроля над тем, кто и где может его использовать». Зачем это кому-то нужно?
hagrawal
1
@hagrawal для тестирования, у вас должна быть возможность поиздеваться над этим
Джемшит Искендеров
15

На самом деле я нашел еще один ответ, не упомянутый здесь: статические методы труднее тестировать.

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

Себастьян Лорбер
источник
2
Но Powermock, похоже, может это сделать
Себастьен Лорбер
6

В большинстве языков программирования классы во многом ускользают от системы типов. Хотя класс со своими статическими методами и переменными является объектом, он очень часто не может реализовать интерфейс или расширить другие классы. По этой причине его нельзя использовать полиморфным образом, поскольку он не может быть подтипом другого типа. Например, если у вас есть интерфейс IFooable, который требуется для нескольких сигнатур методов других классов, объект класса StaticFooне может использоваться вместо IFooable, тогда как FooSingleton.getInstance()может (при условии, FooSingletonреализует IFooable).

Обратите внимание, что, как я прокомментировал ответ Хайнци, синглтон - это шаблон для управления созданием экземпляра. Он заменяется new Class()на Class.getInstance(), что дает авторуClass больше контроля над экземплярами, которые он может использовать для предотвращения создания ненужных экземпляров. Синглтон - это просто особый случай фабричного шаблона, и его следует рассматривать как таковой. Обычное использование делает его скорее особым случаем глобальных реестров, что часто заканчивается неудачей, потому что глобальные реестры не должны использоваться просто так.

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

greetz
back2dos

back2dos
источник
4

Существует компромисс между тем, какой именно. Синглтоны могут иметь состояние, а могут и не иметь, и они относятся к объектам. Если они не сохраняют состояние и используются только для глобального доступа, то лучше использовать static, поскольку эти методы будут быстрее. Но если вы хотите использовать объекты и концепции ООП (полиморфизм наследования), то синглтон лучше.

Рассмотрим пример: java.lang.Runtime - это одноэлементный класс в java. Этот класс допускает разные реализации для каждой JVM. Реализация одна для каждой JVM. Если бы этот класс был статическим, мы не могли бы передавать различные реализации на основе JVM.

Я нашел эту ссылку действительно полезной: http://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html ?

Надеюсь, это поможет!!

Атихска
источник
Этот ответ хорош для включения конкретного примера в реальный мир.
systemovich
2

Для меня «Состояние объекта хочу использовать синглтон, функция хочу использовать статический метод»

Все зависит от того, чего вы хотите. Всякий раз, когда вам нужно состояние объекта (например, полиморфизм, такой как состояние Null вместо состояния по nullумолчанию), singleton является подходящим выбором для вас, тогда как статический метод используется, когда вам нужна функция (получение входных данных, а затем возврат вывода).

Я рекомендую для случая синглтона, он всегда должен быть в том же состоянии после его создания. Он не должен быть ни клонируемым, ни получать какое-либо значение для установки (кроме статической конфигурации из файла, например, файла свойств в java).

PS Производительность между этими двумя различается в миллисекундах, поэтому сначала сосредоточьтесь на архитектуре .

Тоомтарм Кунг
источник
1

Синглтон не является апатридом, он хранит глобальное состояние.

Вот некоторые причины, по которым я могу использовать Singleton:

  • Чтобы избежать утечки памяти
  • Чтобы обеспечить одинаковое состояние для всех модулей в приложении, например, соединение с базой данных
Индиго Правин
источник
Я знаю, но на самом деле синглтон может более или менее не иметь состояния ... Если он не имеет какого-либо атрибута класса ...
Себастьен Лорбер,