Задать вопрос
dauren101
@dauren101
Python, Django ,Vue.js

Для чего нужен singleton?

Для чего нужен singleton?Понятно , что для создания единственного экземпляра класса. А для чего нужен этот единственный экземпляр? Какова цель?
  • Вопрос задан
  • 15142 просмотра
Подписаться 13 Оценить Комментировать
Пригласить эксперта
Ответы на вопрос 9
Adamos
@Adamos
Синглтон - прекрасный индикатор. Если человек задает вопрос, зачем он нужен - значит, этому человеку лень прочитать даже Википедию.
Впрочем, есть утешительный вариант: этот человек просто еще не написал ни одной работоспособной программы, и изучать шаблоны проектирования ему тупо рано.
Ответ написан
@MarkusD
все время мелю чепуху :)
В буквальном смысле синглтон призван упростить владение, инициализацию, контроль времени жизни и доступ к элементам глобального состояния программы. Эта фраза является самой важной. А важнее всего - правильно понять ее.

Подход многократно обличался антипаттерном за то, что "глобальное состояние программы - это зло", не смотря на то, что глобальное состояние продолжает оставаться в программе даже после удаления всех синглтонов из проекта.
Я видел проекты с более чем 50 синглтонами и очень тяжелыми проблемами их связи между собой. В синглтоны без разбора и по незнанке вытаскивали буквально все. Это яркий пример антиподхода применения абсолютно любого паттерна.
Важно понимать что никакой элемент проектирования не является антипаттерном, он приводит к проблемам только при неумелом использовании.

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

В качестве альтернативы синглтонам пропагандируются два других подхода: Registry / Service locator и Dependency injection.
К слову, все альтернативы столь же активно и все так же незаслуженно обзываются антипаттернами. :)

Теперь к примерам.
- DirectX. Для работы с графикой тебе необходимо по одной инстанции интерфейсов IDirect3D и IDirect3DDevice. Эти две инстанции декларируют глобальное состояние программы. Инстанции всех буферов, текстур, шейдеров и поверхностей создаются с использованием этих инстанций. Разумным будет предоставить доступ к инстанциям DirectX через подход синглтона.
- OpenGL старых добрых версий. Процедурный интерфейс OpenGL как бы намекает на отсутствие необходимости в глобальном состоянии. Но не тут то было. Для работы с OpenGL необходимо не просто создать контекст, но еще и помнить поток, в котором этот контекст связан с поверхностью вывода. В многопоточной среде контекстов может быть несколько для параллельной загрузки ресурсов. В этом случае помнить надо уже два потока и два контекста (минимум). Само собой, в синглтоне это глобальное состояние смотрится удобнее.
- Sockets. Не важно какие. Когда твое приложение представляет собой MMO проект и у тебя гора подсистем, постоянно и обособленно общающихся с сервером, сетевое подключение разумно оформить в виде синглтона.
- Assets/Resources - они бывают разные, кешируемые и нет, доступные из сети, с жесткого диска, из подсистемы пререндеринга. Опять же, я несколько раз видел боль и страдания от неоднородного контроля ресурсов без соответствующей подсистемы. А сама подсистема управления ресурсами всегда централизована и лучше всего реализуется именно на синглтоне.

Звук, ввод, многопоточный конвеер задач... вспоминать места явной необходимости синглтонов можно еще долго.
Ответ написан
Комментировать
@jimquery
Проще, думаю, объяснить на примере с базой данных.
Допустим у тебя есть программа с несколькими формами, каждая из которых использует какие-либо данные. Если на каждой форме создавать свой объект БД и писать/читать через него данные, то в один момент времени данные между формами могут отличаться и противоречить друг другу.
Для решения этой проблемы создаёшь экземпляр базы данных в единственном состоянии (singletone) и используешь ссылку на него в каждой форме. При этом на каждой форме будут использоваться одинаковые данные.
Ответ написан
Комментировать
@protven
Как человек, который может написать штук пять реализаций синглтона и который их не использует, могу сказать точно что это уже скорее вопрос для собеседования, чем из реальной жизни. В целом - иногда нужен, но проще нагуглить.
Ответ написан
Комментировать
@Quieteroks
php программист
Это же элементарно. Изначально, как замена глобальным переменным. Он один и следовательно все обращения к нему несут изменения во всём проекте. В одном месте вы создали подключение к базе и дальше можете уже использовать его в любой части программы, не пересоздавая подключение и не передавая каждый раз его как аргумент функции.

На самом деле достаточно прочитать любое его описание и становится понятнее.
Ответ написан
@trubel
Посмотрите вебинар по паттернам на Хеклете, где-то с 1:20 начинается обсуждение синглатона, к концу видео подводятся итоги.
Если кратко, синглатон — замена глобальной переменной, чтобы таскать с собой контекст приложения, его использование несет определенные ограничения. Лучше для контекста приложения использовать dependency container.
Вообще рекомендую посмотреть видео целиком, четко расставляет по полочкам про паттерны.
Ответ написан
Комментировать
@kahi4
Синглтон нужен в первую очередь чтобы создавать лишний геморрой. На первых порах он кажется таким замечательным и прекрасным, но когда-то вы завозите тестирование в свое приложение и начинаются большие проблемы. А потом оказывается, что и соединений с базой данных нужно два по той или иной причине, и настройки нужно разносить в зависимости пользователя и каких-то других внешних факторов, что в итоге приводит к переписыванию большей части кодовой базы. Иными словами -- прежде, чем использовать его, нужно подумать хорошо и посмотреть -- можно ли обойтись без него.

Но придуман он все таки с благой целью: инкапсулировать в себе точки доступа к внешним ресурсам -- как правило, вам нужно одно соединение с базой данных, одна точка с настройками и прочим. И вот, чтобы не создавать каждый раз новый экземпляр, чтобы не выделять ресурсы, чтобы иметь возможность реализовать ленивую (lazy) загрузку и был разработан паттерн, который позволяет обратиться к ресурсу из любой точке приложения и не пробрасывать экземпляры классов/параметры соединения/прочее в каждую функцию, что часто неудобно.
Ответ написан
Комментировать
@WAERZ
Есть
private static $instance = null
И есть
public static function getInstance(){
if (self::instance === null){
 self::instance = new self();
} 
return self::instance;
}

То есть мы помещаем в переменную instance объект класса и потом через getInstance получаем этот объект, а не создаем каждый раз. Это удобно, но нужно использовать только там где стоит. Например для подключения к базе данных.
Ответ написан
Комментировать
@cap_nemo
Иногда возникает необходимость в чем-то единственном...

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

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

Общий смысл - нужно, что-то уникальное, используй его.
Некоторые ребята крутят миниюлу из металла в таких случаях :-)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

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