По шаблонам проектирования:Когда мне следует использовать синглтон?[закрыто]

StackOverflow https://stackoverflow.com/questions/228164

  •  03-07-2019
  •  | 
  •  

Вопрос

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

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

Это было полезно?

Решение

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

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

Ведение журнала - это конкретный пример "приемлемого" Синглтон, потому что это не влияет на выполнение вашего кода. Отключите ведение журнала, выполнение кода остается прежним. Включите это, то же самое. Миско описывает это следующим образом в первопричина синглетонов , " информация здесь течет одним способом: из вашего приложения в регистратор. Несмотря на то, что средства ведения журнала находятся в глобальном состоянии, поскольку никакие данные не поступают из средств ведения журнала в ваше приложение, средства ведения журнала являются приемлемыми. & Quot;

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

Узнайте больше в Синглтоне. Я люблю вас, но вы меня опускаете.

Другие советы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

$gb->config['hostname']

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

$gb->lang['ENTER_USER']

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

$template

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

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

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

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

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

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

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

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

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

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

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

Эд.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top