О шаблонах проектирования: когда следует использовать синглтон?

Прославленная глобальная переменная - становится славным глобальным классом. Некоторые говорят, что ломают объектно-ориентированный дизайн.

Приведите мне сценарии, кроме старого доброго регистратора, где имеет смысл использовать синглтон.


person Setori    schedule 23.10.2008    source источник
comment
Изучая erlang, я предпочитаю этот подход, а именно неизменность и передачу сообщений.   -  person Setori    schedule 26.11.2009
comment
Что не конструктивно в этом вопросе? Я вижу конструктивный ответ ниже.   -  person mk12    schedule 26.06.2013
comment
Фреймворк внедрения зависимостей - это очень сложный синглтон, который выдает объект….   -  person Ian Ringrose    schedule 10.02.2014
comment
Синглтон можно использовать в качестве объекта-менеджера между экземплярами других объектов, поэтому должен быть только один экземпляр синглтона, в котором каждый другой экземпляр должен взаимодействовать через экземпляр синглтона.   -  person Levent Divilioglu    schedule 07.12.2015
comment
У меня есть побочный вопрос: любая реализация Singleton также может быть реализована с использованием статического класса (с помощью метода factory / init) - без фактического создания экземпляра класса (можно сказать, что статический класс является своего рода реализацией Singleton, но ...) - почему следует использовать фактический синглтон (единственный экземпляр класса, который гарантирует его единственный) вместо статического класса? Единственная причина, о которой я могу думать, - это, возможно, семантика, но даже в этом смысле варианты использования синглтона на самом деле не требуют отношения класса и экземпляра по определению ... так ... почему?   -  person Yuval A.    schedule 01.02.2019


Ответы (21)


В своих поисках истины я обнаружил, что на самом деле существует очень мало «приемлемых» причин для использования синглтона.

Одна из причин, которая имеет тенденцию снова и снова появляться в Интернете, - это класс "ведения журнала" (о котором вы упомянули). В этом случае синглтон можно использовать вместо одного экземпляра класса, потому что класс ведения журнала обычно должен использоваться снова и снова, до тошноты каждым классом в проекте. Если каждый класс использует этот класс ведения журнала, внедрение зависимостей становится громоздким.

Ведение журнала - это конкретный пример «приемлемого» синглтона, поскольку он не влияет на выполнение вашего кода. Отключите ведение журнала, выполнение кода останется прежним. Включите, то же самое. Миско объясняет это следующим образом: Основная причина синглтонов, «Информация здесь течет в одном направлении: из вашего приложения в регистратор. Несмотря на то, что регистраторы имеют глобальное состояние, поскольку никакая информация не поступает от регистраторов в ваше приложение, регистраторы приемлемы».

Я уверен, что есть и другие веские причины. Алекс Миллер, в "Ненавижу паттерны», где говорится о локаторах сервисов и пользовательском интерфейсе на стороне клиента, которые, возможно, также являются «приемлемыми» вариантами.

Читайте больше на Синглтоне. Я люблю тебя, но ты меня подводишь.

person CodingWithoutComments    schedule 23.10.2008
comment
Не могли бы вы привести еще несколько примеров? А как насчет того, что управляет сеансами по конкретному запросу? - person CMCDragonkai; 17.09.2013
comment
не могли бы вы снова предоставить текущую ссылку на последнюю строку? Я получаю сообщение об ошибке DNS (домен не существует). - person Arne Mertz; 01.11.2013
comment
@ArneMertz, наверное, это тот. - person Attacktive; 21.12.2013
comment
@CodingWithoutComments, подходит ли Singleton Sql Helper для небольшого проекта? - person KumarHarsh; 28.08.2014
comment
Почему нельзя просто использовать глобальный объект? Почему это должен быть синглтон? - person Shoe; 08.12.2015
comment
Я думаю, что статический метод для ведения журнала утилит? - person Skynet; 22.01.2016
comment
Синглтоны лучше всего подходят для управления ресурсами. Например, HTTP-соединения. Вы не хотите устанавливать 1 миллион http-клиентов для одного клиента, это безумно расточительно и медленно. Таким образом, синглтон с HTTP-клиентом из пула соединений будет намного быстрее и удобнее в использовании. - person Cogman; 10.06.2016
comment
Я знаю, что это старый вопрос, и информация в этом ответе отличная. Однако мне трудно понять, почему это принятый ответ, когда OP четко указан: Дайте мне сценарии, кроме старого доброго регистратора, где имеет смысл использовать синглтон. - person Francisco C.; 04.01.2017
comment
Потому что таких сценариев нет, и вот почему правильный ответ. - person spectras; 23.01.2020
comment
Я все еще в замешательстве. Класс Logger будет иметь метод LogException. Обязанности этого метода всегда будут одинаковыми. Почему мы не можем использовать этот метод как Static в классе Static? - person Dragon Warrior; 30.04.2020
comment
пока ваш (по умолчанию) регистратор не отправит сообщение в сеть, и вы не захотите использовать классы модульного тестирования, которые регистрируют ... - person YSC; 26.05.2020
comment
@Cogman Нет, в этом случае у вас должен быть один объект пула соединений, но он не должен быть одноэлементным. - person user253751; 01.07.2020
comment
Когда спрашивают об синглтоне, большинство людей имеют в виду один объект - еще один шаблон, скрывающийся внутри синглтона, который является лишь одним из способов его реализации. Одиночные объекты абсолютно законны и могут быть обернуты Service Locator и Factory Method. Поскольку они вызывают трудности с многопоточностью, их следует использовать с осторожностью. Не дайте себя одурачить - независимо от реализации, отдельные объекты всегда связаны с каким-то общим глобальным состоянием. - person raiks; 07.08.2020

Кандидат в Singleton должен удовлетворять трем требованиям:

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

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

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

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

person metao    schedule 23.10.2008
comment
Я не согласен с пунктом 2. Пункт 3 на самом деле не является причиной (только потому, что вы можете, это не значит, что вам следует), а пункт 1 - хороший момент, но я все еще не вижу в нем пользы. Допустим, общий ресурс - это диск или кеш db. Вы можете добавить еще один диск или создать кеш БД, ориентированный на другую вещь (например, кеш для специализированной таблицы для одного потока, а другой - более общего назначения). - person ; 01.07.2011
comment
Я думаю, вы пропустили слово «кандидат». Кандидат в Singleton должен удовлетворять трем требованиям; просто потому, что что-то соответствует требованиям, не означает, что это должен быть синглтон. Могут быть и другие конструктивные факторы :) - person metao; 04.07.2011
comment
Диспетчер очереди печати не соответствует критериям. Для тестирования вам может потребоваться программа буферизации тестовой печати, которая на самом деле не печатает. - person user253751; 01.07.2020

Чтение файлов конфигурации, которые следует читать только во время запуска, и их инкапсуляция в Singleton.

person Paul Croarkin    schedule 23.10.2008
comment
Аналогично Properties.Settings.Default в .NET. - person Nick Bedford; 05.12.2011
comment
@Paul, лагерь no-singleton будет утверждать, что объект конфигурации должен просто передаваться функциям, которые в нем нуждаются, вместо того, чтобы делать его глобально доступным (также известным как singleton). - person Pacerier; 25.06.2014
comment
Не согласен. Если конфигурацию перенести в базу данных, все испортилось. Если путь к конфигурации зависит от чего-либо, кроме этого синглтона, эти вещи тоже должны быть статическими. - person rr-; 29.08.2015
comment
@PaulCroarkin Не могли бы вы подробнее рассказать об этом и объяснить, чем это полезно? - person AlexG; 20.04.2017
comment
@ rr - если конфигурация перемещается в базу данных, она все еще может быть инкапсулирована в объект конфигурации, который будет передан функциям, которые в этом нуждаются. (P.S. Я не в лагере одиночек). - person Will Sheppard; 06.04.2020
comment
Конфигурация (в том смысле, о котором мы говорим) всегда должна быть доступной только для чтения, вы даже можете добиться этого с помощью базы данных, когда разрешения установлены правильно. Прохождение конфигурации повсюду рано или поздно заканчивается тем, что кто-то пытается настроить ее на ходу, нет, спасибо, но просто нет ... - person jave.web; 22.02.2021

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

Или подключение к базе данных, файловый менеджер и т. Д.

person Vincent Ramdhanie    schedule 23.10.2008
comment
Я слышал этот пример диспетчера очереди печати принтера, и я думаю, что это отчасти неубедительно. Кто сказал, что у меня не может быть более одного диспетчера очереди печати? Что, черт возьми, такое диспетчер очереди печати принтера? Что делать, если у меня разные типы принтеров, которые не могут конфликтовать или использовать разные драйверы? - person 1800 INFORMATION; 23.10.2008
comment
Это просто пример ... для любой ситуации, которую кто-либо использует в качестве примера, вы сможете найти альтернативный дизайн, который сделает этот пример бесполезным. Предположим, диспетчер очереди печати управляет одним ресурсом, который используется несколькими компонентами. Оно работает. - person Vincent Ramdhanie; 23.10.2008
comment
Это классический пример «Банды четырех». Я думаю, что ответ с реальным вариантом использования был бы более полезным. Я имею в виду ситуацию, когда вы действительно считали, что Синглтон - лучшее решение. - person Andrei Vajna II; 16.09.2009
comment
Общий ресурс, на мой взгляд, является слишком общим примером. Как вы можете проверить, что объекты, использующие диспетчер очереди печати, работают правильно перед лицом неисправного диспетчера очереди печати, когда вы не можете внедрить неисправную реализацию диспетчера очереди печати? хотя краткий и неинформативный, принятый ответ - гораздо более безопасный подход в моей книге - person Rune FS; 20.08.2010
comment
Что, черт возьми, такое диспетчер очереди печати принтера? - person RayLoveless; 17.05.2018
comment
@ 1800INFORMATION Итак, что такое диспетчер очереди печати принтера после стольких лет? .. - person Sajuuk; 27.05.2019
comment
@Sajuuk диспетчер очереди печати - это абстракция приложения, которое отвечает за управление и контроль всех принтеров на данном устройстве. - person andresantacruz; 12.12.2019
comment
@andresantacruz а, значит, если у меня два устройства, мне нужно два из них? - person user253751; 01.07.2020

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

person Martin Beckett    schedule 23.10.2008
comment
Пользовательский язык может быть только одноэлементным при условии, что только один пользователь может использовать систему. - person Samuel Åslund; 10.04.2014
comment
… И этот пользователь говорит только на одном языке. - person spectras; 23.01.2020
comment
@ SamuelÅslund Если это настольное приложение, это справедливое предположение - person user253751; 01.07.2020
comment
@ user253751 Да, это так, пока его внезапно не исчезло, потребовалось много работы, чтобы преобразовать синглтон языка Javas в нечто, что могло бы поддерживать интернационализированные веб-сайты. Я обнаружил, что использование синглтона в качестве параметра часто является разумным компромиссом, путем извлечения экземпляра синглтона в вызывающей стороне функция, использующая его, может быть протестирована изолированно и повторно использована без особых проблем, и явно глобальный параметр не нужно передавать в длинных стеках вызовов. Многие языки поддерживают параметры по умолчанию, которые можно использовать, чтобы избежать дублирования. - person Samuel Åslund; 05.07.2020
comment
@spectras, хотя я согласен, на самом деле это обычный случай, например, ОС, в которой последнее, что вам нужно, - это смешанные языки по всему экрану, даже если пользователь говорил больше. - person jave.web; 22.02.2021
comment
@ jave.web на самом деле меня бы сильно раздражала ОС, которая не позволяет мне печатать на нескольких языках (например: выделение орфографии, помечающее один из моих языков как неправильный) или смешанные настройки (например: использовать английский, но градусы Цельсия, км и мой местный формат даты). - person spectras; 22.02.2021
comment
(на самом деле я думаю, что многие приложения могут обойтись только одним языком, поскольку пользователи, использующие несколько языков, обычно используют только один для конкретной деятельности, но ОС определенно является плохим примером, поскольку она используется во всех действиях). - person spectras; 22.02.2021
comment
@spectras не уверен, что мы говорим об одном и том же, я говорю об интерфейсе и меню ОС, вы говорите о поддержке языка клавиатуры и настройках формата даты, которые совершенно разные вещи , Цельсий, Кельвин и км - единственные реальные единицы: D - person jave.web; 22.02.2021

Управление подключением (или пулом подключений) к базе данных.

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

person Federico A. Ramponi    schedule 23.10.2008
comment
Разве генератор подключения к базе данных не был бы примером Factory? - person Ken; 02.11.2010
comment
@Ken, вы бы хотели, чтобы эта фабрика была одноэлементной почти во всех случаях. - person Chris Marisic; 24.05.2011
comment
@Federico, в лагере нет-синглтонов будет указано, что эти соединения с базой данных должны быть просто переданы функциям, которые в них нуждаются, вместо того, чтобы делать их глобально доступными (также известными как синглтон). - person Pacerier; 25.06.2014
comment
Для этого вам действительно не нужен синглтон. Его можно вводить инъекционно. - person Nestor Ledon; 10.02.2017
comment
@NestorLedon на самом деле сводится к тому, как часто вы его используете, это можно сделать в обоих направлениях, но если вы будете использовать что-то в 99% приложения, внедрение зависимостей может не подойти. С другой стороны, если вы используете его только иногда, но все равно должно быть то же самое, то dep.inj. может быть путь :) - person jave.web; 22.02.2021
comment
@ java.web Nooooooooo. Вообще говоря, чем больше файлов он касается, тем больше инъекций вы хотите. Это позволяет вам менять технологии под капотом, что отлично подходит для зависимостей хранилища. Я немного ослаблю вас, если синглтон абстрагируется с помощью интерфейсов, потому что тогда, по крайней мере, вы можете обновить там экземпляр. - person Nestor Ledon; 23.02.2021

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

При использовании синглтонов вы должны убедиться, что случайно не скрываете зависимости. В идеале синглтоны (как и большинство статических переменных в приложении) должны быть настроены во время выполнения вашего кода инициализации для приложения (static void Main () для исполняемых файлов C #, static void main () для исполняемых файлов java), а затем переданы в все остальные классы, экземпляры которых требуют этого. Это помогает поддерживать тестируемость.

person Adam Ness    schedule 23.10.2008

Один из способов использования синглтона - охват экземпляра, в котором должен быть один «брокер», контролирующий доступ к ресурсу. Синглтоны хороши в регистраторах, потому что они обеспечивают доступ, скажем, к файлу, в который можно только записывать. Для чего-то вроде ведения журнала они предоставляют способ абстрагироваться от записи в нечто вроде файла журнала - вы можете обернуть механизм кеширования в свой синглтон и т. Д.

Также подумайте о ситуации, когда у вас есть приложение с множеством окон, потоков и т. Д., Но которому требуется единая точка связи. Однажды я использовал один для управления заданиями, которые я хотел запустить для своего приложения. Синглтон отвечал за сериализацию заданий и отображение их статуса для любой другой интересующей части программы. В таком сценарии вы можете рассматривать синглтон как своего рода «серверный» класс, работающий внутри вашего приложения ... HTH

person Dave Markle    schedule 23.10.2008
comment
Регистраторы чаще всего являются синглетонами, поэтому объекты регистрации не нужно передавать. Любая достойная реализация потока журнала гарантирует, что одновременная запись невозможна, независимо от того, является ли это синглтоном или нет. - person metao; 23.10.2008

Я думаю, что использование singleton можно рассматривать как то же самое, что и отношения «многие к одному» в базах данных. Если у вас есть много разных частей вашего кода, которые должны работать с одним экземпляром объекта, именно здесь имеет смысл использовать синглтоны.

person daalbert    schedule 23.05.2011

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

История синглтона Test :: Builder поучительна. Вызов new() всегда дает один и тот же объект. Во-первых, все данные хранились как переменные класса, причем в самом объекте ничего не было. Это работало, пока я не захотел протестировать Test :: Builder на самом себе. Затем мне понадобились два объекта Test :: Builder, один из которых был настроен как фиктивный, для захвата и тестирования его поведения и вывода, а другой - как настоящий тестовый объект. На этом этапе Test :: Builder был преобразован в реальный объект. Одноэлементный объект хранился как данные класса, и new() всегда его возвращал. create() был добавлен для создания нового объекта и включения тестирования.

В настоящее время пользователи хотят изменить некоторые поведения Test :: Builder в своем собственном модуле, но оставить другие в покое, в то время как история тестирования остается общей для всех модулей тестирования. Сейчас происходит то, что монолитный объект Test :: Builder разбивается на более мелкие части (история, вывод, формат ...), а экземпляр Test :: Builder собирает их вместе. Теперь Test :: Builder больше не должен быть синглтоном. Его составляющие, как и история, могут быть. Это опускает негибкую необходимость синглтона на уровень ниже. Это дает пользователю больше возможностей комбинировать элементы. Более мелкие одноэлементные объекты теперь могут просто хранить данные, а содержащиеся в них объекты решают, как их использовать. Он даже позволяет классу, не относящемуся к Test :: Builder, подыгрывать, используя историю Test :: Builder и выводя синглтоны.

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

person Schwern    schedule 21.12.2008

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

person Dean J    schedule 30.11.2009
comment
Почему бы вам просто не загрузить данные один раз и передать объект конфигурации по мере необходимости? - person lagweezle; 29.09.2016
comment
что с прохожими ??? Если бы мне пришлось передавать каждый объект, который мне нужен, у меня были бы конструкторы с 20 аргументами ... - person Enerccio; 18.04.2018
comment
@Enerccio. Если у вас есть объекты, которые зависят от 20 различных других без инкапсуляции, у вас уже есть серьезные проблемы с дизайном. - person spectras; 23.01.2020
comment
@spectras Я? Если я реализую графический интерфейс, мне понадобятся: репозиторий, локализация, данные сеанса, данные приложения, родительский элемент виджета, данные клиента, диспетчер разрешений и, возможно, многое другое. Конечно, некоторые можно объединить, но почему? Лично я использую пружину и аспекты, чтобы просто автоматически связать все эти зависимости с классом виджета, и это все разделяет. - person Enerccio; 26.01.2020
comment
Если у вас такое большое состояние, вы можете рассмотреть возможность реализации фасада, дающего представление о соответствующих аспектах конкретного контекста. Почему? Потому что это позволит создать чистый дизайн без антипаттернов конструктора с одним элементом или с 29 аргументами. На самом деле сам факт того, что ваш графический интерфейс обращается ко всем этим вещам, вопиет о нарушении принципа единой ответственности. - person spectras; 26.01.2020

Общие ресурсы. Особенно в PHP - это класс базы данных, класс шаблона и класс хранилища глобальных переменных. Все они должны использоваться всеми модулями / классами, которые используются в коде.

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

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

$gb->config['hostname']

или имея все языковые значения в массиве, например:

$gb->lang['ENTER_USER']

В конце выполнения кода для страницы вы получите, скажем, уже зрелую версию:

$template

Синглтон, $gb синглтон, в котором есть массив lang для замены, а весь вывод загружен и готов. Вы просто заменяете их ключами, которые теперь присутствуют в значении страницы зрелого объекта шаблона, а затем передаете его пользователю.

Большим преимуществом этого является то, что вы можете выполнять ЛЮБУЮ постобработку, которая вам нравится, на чем угодно. Вы можете передать все языковые значения в Google Translate или другую службу перевода и получить их обратно, и заменить их на свои места, например переведенные. или вы можете заменить в структурах страниц или строках содержимого, как хотите.

person Ozgur Zeren    schedule 02.11.2010
comment
Возможно, вы захотите разбить свой ответ на несколько абзацев и заблокировать сегменты кода для удобства чтения. - person Justin; 02.11.2010

Как все уже говорили, общий ресурс - а именно то, что не может обрабатывать одновременный доступ.

Один конкретный пример, который я видел, - это средство записи индекса поиска Lucene.

person Mike    schedule 23.10.2008

Вы можете использовать Singleton при реализации паттерна State (как показано в книге GoF). Это связано с тем, что конкретные классы State не имеют собственного состояния и выполняют свои действия в терминах класса контекста.

Вы также можете сделать Abstract Factory одноэлементным.

person Emile Cormier    schedule 02.02.2010
comment
Это тот случай, с которым я сейчас работаю в проекте. Я использовал шаблон состояния, чтобы удалить повторяющийся условный код из методов контекста. Состояние не имеет собственных переменных экземпляра. Однако я сомневаюсь в том, стоит ли мне делать их синглтоны. Каждый раз, когда состояние переключается, создается новый экземпляр. Это кажется расточительным, потому что экземпляр никак не может отличаться от другого (потому что нет переменных экземпляра). Я пытаюсь понять, почему мне не следует его использовать. - person kiwicomb123; 23.03.2017
comment
@ kiwicomb123 Постарайтесь сделать setState() ответственным за принятие решения о политике создания состояния. Это помогает, если ваш язык программирования поддерживает шаблоны или обобщения. Вместо синглтона вы можете использовать шаблон Monostate, где создание экземпляра объекта состояния заканчивается повторным использованием того же глобального / статического объекта состояния. Синтаксис для изменения состояния может остаться неизменным, поскольку вашим пользователям не нужно знать, что созданное состояние является моносостояниями. - person Emile Cormier; 23.03.2017
comment
Хорошо, в моем состоянии я мог бы просто сделать все методы статическими, поэтому всякий раз, когда создается новый экземпляр, у него не будет таких же накладных расходов? Я немного сбит с толку, мне нужно прочитать о шаблоне Monostate. - person kiwicomb123; 26.03.2017
comment
@ kiwicomb123 Нет, Monostate не делает всех членов статичными. Лучше, если вы прочтете об этом, а затем проверьте SO на связанные вопросы и ответы. - person Emile Cormier; 27.03.2017
comment
Я считаю, что у этого должно быть больше голосов. Абстрактная фабрика достаточно распространена, и поскольку фабрики не имеют состояния, стабильны и не могут быть реализованы с помощью статических методов (в Java), которые не переопределяются, использование синглтона должно быть нормальным. - person DPM; 27.08.2019

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

  • Один объект - мне нужен только один экземпляр объекта в программе.
  • Синглтон - создайте класс со статическим полем. Добавьте статический метод, возвращающий это поле. Лениво создайте экземпляр поля при первом вызове. Всегда возвращайте один и тот же объект.
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton instance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Как видите, шаблон Singleton в его канонической форме не очень удобен для тестирования. Однако это можно легко исправить: просто заставьте синглтон реализовывать интерфейс. Назовем его Testable Singleton :)

public class Singleton implements ISingleton {
    private static Singleton instance;

    private Singleton() {}

    public static ISingleton instance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

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

Если мы удалим шаблон Singleton, по сути, речь идет о ленивой инициализации:

public static ISingleton instance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

В этом вся причина его существования. И это шаблон "Один объект". Забираем и помещаем в заводской метод, например:

public class SingletonFactory {
    private static ISingleton instance;

    // Knock-knock. Single Object here
    public static ISingleton simpleSingleton() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

В чем разница с нашим тестируемым синглтоном? Нет ни одного, потому что это суть паттерна одного объекта - неважно, реализуете ли вы его как синглтон, фабричный метод или локатор службы. У вас все еще есть какое-то общее глобальное состояние. Это может стать проблемой, если к нему обращаются из нескольких потоков. Вам нужно будет синхронизировать simpleSingleton() и справиться со всеми проблемами многопоточности.

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

Резюме:

  1. Большинство людей, которые упоминают синглтон, имеют в виду один объект
  2. Один из популярных способов его реализации - паттерн Синглтон.
  3. У него есть недостатки, которые можно устранить.
  4. Однако большая часть сложности синглтона коренится в сложности одного объекта.
  5. Независимо от того, как вы создаете экземпляр своего Единого объекта, он все еще существует, будь то локатор службы, заводской метод или что-то еще.
  6. Вы можете перенести сложность на контейнер DI, который (надеюсь) хорошо протестирован.
  7. Иногда использование контейнера DI затруднительно - представьте, что вводите LOGGER в каждый класс.
person raiks    schedule 07.08.2020

Я использую его для объекта, инкапсулирующего параметры командной строки при работе с подключаемыми модулями. Основная программа не знает, каковы параметры командной строки для загружаемых модулей (и даже не всегда знает, какие модули загружаются). например, основная загрузка A, которая сама по себе не нуждается в каких-либо параметрах (так почему он должен принимать дополнительный указатель / ссылку / что угодно, я не уверен - похоже на загрязнение), затем загружает модули X, Y и Z. Два из них, скажем, X и Z, нуждаются (или принимают) параметры, поэтому они обращаются к синглтону командной строки, чтобы сообщить ему, какие параметры принимать, а во время выполнения они перезванивают, чтобы узнать, действительно ли пользователь указал какие-либо из них.

Во многих отношениях синглтон для обработки параметров CGI будет работать аналогично, если вы используете только один процесс для каждого запроса (другие методы mod_ * этого не делают, поэтому там будет плохо - таким образом, аргумент, который говорит, что вы не должны: t используйте синглтоны в мире mod_cgi на случай, если вы переносите на mod_perl или в любой другой мир).

person Tanktalus    schedule 23.10.2008

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

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

person smaclell    schedule 23.10.2008

Я думаю, если ваше приложение имеет несколько уровней, например, презентацию, домен и модель. Синглтон - хороший кандидат на роль сквозного слоя. И предоставлять услуги каждому уровню в системе.

По сути, Singleton обертывает сервис, например, такой как ведение журнала, аналитика, и предоставляет его другим уровням в системе.

И да, singleton должен следовать принципу единой ответственности.

person Christo Kumar    schedule 23.09.2020

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

Допустим, у вас есть приложение, которому требуется база данных для обработки операций CRUD. В идеале вы должны использовать один и тот же объект подключения к базе данных для доступа к базе данных и выполнения операций CRUD.

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

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

person Lakindu Hewawasam    schedule 11.11.2020

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

person Bennington    schedule 24.06.2021

Возможно, пример с кодом.

Здесь ConcreteRegistry - это синглтон в игре в покер, который позволяет поведениям на всем пути вверх по дереву пакетов обращаться к немногим, основным интерфейсам игры (то есть фасадам для модели, представления, контроллера, среды и т. Д.):

http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html

Ed.

person Community    schedule 24.10.2008
comment
Ссылка теперь не работает, но если вы регистрируете информацию о представлении в синглтоне, доступ к которому будет осуществляться во всем приложении, вы упускаете суть MVC. Представление обновляется (и взаимодействует с) контроллером, который использует модель. Как здесь звучит, это, вероятно, неправильное использование синглтона и рефакторинг в порядке. - person drharris; 28.05.2010