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

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

Дайте мне сценарии, кроме старого старого журнала, где имеет смысл использовать синглтон.

Ответы

Ответ 1

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

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

Регистрация - это конкретный пример "приемлемого" Singleton, потому что он не влияет на выполнение вашего кода. Отключить ведение журнала, выполнение кода остается неизменным. Включите его, то же самое. Misko делает это следующим образом в Root Cause of Singletons: "Информация здесь протекает в одном направлении: из вашего приложения в регистратор. Хотя регистраторы являются глобальным состоянием, поскольку никакая информация не поступает из регистраторов в ваше приложение, регистраторы приемлемы".

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

Ответ 6

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

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

Ответ 7

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

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

Ответ 8

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

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

Ответ 9

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

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

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

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

Ответ 10

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

Ответ 11

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

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

Ответ 12

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

Ответ 13

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

Вы также можете сделать абстрактный Factory синглтон.

Ответ 14

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

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

Глобальная переменная depot singleton предоставляет вам глобальное, надежное и легко используемое хранилище переменных. Это очень убирает ваш код. Представьте, что все значения конфигурации в массиве в одном столбце, например $gb->config['hostname'], или все значения языка в массиве, например $gb->lang['ENTER_USER']. В конце запуска кода для страницы вы получаете, скажем, теперь зрелый сингл $template singleton, a $gb singleton, который имеет массив lang для его замены, и все выходные данные загружаются и готовятся. Вы просто заменяете их на ключи, которые теперь присутствуют на странице зрелой страницы объекта шаблона, а затем подают ее пользователю.

Огромное преимущество этого заключается в том, что вы можете делать ЛЮБОЙ пост-обработку, которая вам нравится на чем угодно. Вы можете передать все языковые значения в google translate или другой перевод, и вернуть их, и заменить их на свои места, например, переведенные. или, вы можете заменить в структурах страниц или строках контента, как хотите.

Ответ 15

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

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

Ответ 16

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

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

Ответ 17

Пример с кодом, возможно.

Здесь ConcreteRegistry представляет собой однопользовательский режим в покерной игре, который позволяет поведениям вплоть до дерева пакетов получить доступ к нескольким основным функциям игры (то есть к фасадам модели, представления, контроллера, среды и т.д..):

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

Под ред.

Ответ 18

1 - Комментарий к первому ответу:

Я не согласен со статическим классом Logger. это может быть практичным для реализации, но оно не может быть заменено для модульного тестирования. Статический класс не может быть заменен тестовым двойным. Если вы не unit test, здесь вы не увидите проблемы.

2 - Я стараюсь не создавать одиночный кинематограф вручную. Я просто создаю простой объект с конструкторами, которые позволяют мне вводить соавторов в объект. Если мне нужен синглтон, я бы использовал инфраструктуру inyection зависимости (Spring.NET, Unity для .NET, Spring для Java) или какой-либо другой.