Прославленная глобальная переменная - становится славным глобальным классом. Некоторые говорят, что ломают объектно-ориентированный дизайн.
Приведите мне сценарии, кроме старого доброго регистратора, где имеет смысл использовать синглтон.
Прославленная глобальная переменная - становится славным глобальным классом. Некоторые говорят, что ломают объектно-ориентированный дизайн.
Приведите мне сценарии, кроме старого доброго регистратора, где имеет смысл использовать синглтон.
В своих поисках истины я обнаружил, что на самом деле существует очень мало «приемлемых» причин для использования синглтона.
Одна из причин, которая имеет тенденцию снова и снова появляться в Интернете, - это класс "ведения журнала" (о котором вы упомянули). В этом случае синглтон можно использовать вместо одного экземпляра класса, потому что класс ведения журнала обычно должен использоваться снова и снова, до тошноты каждым классом в проекте. Если каждый класс использует этот класс ведения журнала, внедрение зависимостей становится громоздким.
Ведение журнала - это конкретный пример «приемлемого» синглтона, поскольку он не влияет на выполнение вашего кода. Отключите ведение журнала, выполнение кода останется прежним. Включите, то же самое. Миско объясняет это следующим образом: Основная причина синглтонов, «Информация здесь течет в одном направлении: из вашего приложения в регистратор. Несмотря на то, что регистраторы имеют глобальное состояние, поскольку никакая информация не поступает от регистраторов в ваше приложение, регистраторы приемлемы».
Я уверен, что есть и другие веские причины. Алекс Миллер, в "Ненавижу паттерны», где говорится о локаторах сервисов и пользовательском интерфейсе на стороне клиента, которые, возможно, также являются «приемлемыми» вариантами.
Читайте больше на Синглтоне. Я люблю тебя, но ты меня подводишь.
Кандидат в Singleton должен удовлетворять трем требованиям:
Если ваш предлагаемый синглтон имеет только одно или два из этих требований, редизайн почти всегда является правильным вариантом.
Например, диспетчер очереди печати принтера вряд ли будет вызываться из более чем одного места (меню «Печать»), поэтому вы можете использовать мьютексы для решения проблемы одновременного доступа.
Простой регистратор - наиболее очевидный пример возможно действительного синглтона, но это может измениться с более сложными схемами регистрации.
Чтение файлов конфигурации, которые следует читать только во время запуска, и их инкапсуляция в Singleton.
Properties.Settings.Default в .NET.
- person Nick Bedford; 05.12.2011
Вы используете синглтон, когда вам нужно управлять общим ресурсом. Например, диспетчер очереди печати принтера. В вашем приложении должен быть только один экземпляр диспетчера очереди печати, чтобы избежать конфликтующих запросов на один и тот же ресурс.
Или подключение к базе данных, файловый менеджер и т. Д.
Разумны синглтоны только для чтения, хранящие некоторое глобальное состояние (язык пользователя, путь к файлу справки, путь к приложению). Будьте осторожны при использовании синглтонов для управления бизнес-логикой - один почти всегда заканчивается множеством
Управление подключением (или пулом подключений) к базе данных.
Я бы использовал его также для извлечения и хранения информации о внешних файлах конфигурации.
Синглтон следует использовать при управлении доступом к ресурсу, который используется всем приложением, и потенциально иметь несколько экземпляров одного и того же класса было бы деструктивно. Обеспечение потоковой безопасности доступа к общим ресурсам - один из очень хороших примеров того, где такой шаблон может быть жизненно важным.
При использовании синглтонов вы должны убедиться, что случайно не скрываете зависимости. В идеале синглтоны (как и большинство статических переменных в приложении) должны быть настроены во время выполнения вашего кода инициализации для приложения (static void Main () для исполняемых файлов C #, static void main () для исполняемых файлов java), а затем переданы в все остальные классы, экземпляры которых требуют этого. Это помогает поддерживать тестируемость.
Один из способов использования синглтона - охват экземпляра, в котором должен быть один «брокер», контролирующий доступ к ресурсу. Синглтоны хороши в регистраторах, потому что они обеспечивают доступ, скажем, к файлу, в который можно только записывать. Для чего-то вроде ведения журнала они предоставляют способ абстрагироваться от записи в нечто вроде файла журнала - вы можете обернуть механизм кеширования в свой синглтон и т. Д.
Также подумайте о ситуации, когда у вас есть приложение с множеством окон, потоков и т. Д., Но которому требуется единая точка связи. Однажды я использовал один для управления заданиями, которые я хотел запустить для своего приложения. Синглтон отвечал за сериализацию заданий и отображение их статуса для любой другой интересующей части программы. В таком сценарии вы можете рассматривать синглтон как своего рода «серверный» класс, работающий внутри вашего приложения ... HTH
Я думаю, что использование singleton можно рассматривать как то же самое, что и отношения «многие к одному» в базах данных. Если у вас есть много разных частей вашего кода, которые должны работать с одним экземпляром объекта, именно здесь имеет смысл использовать синглтоны.
Практический пример синглтона можно найти в 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 и выводя синглтоны.
Похоже, существует взаимопонимание между координацией данных и гибкостью поведения, которую можно смягчить, поместив синглтон вокруг только общих данных с наименьшим объемом поведения, насколько это возможно для обеспечения целостности данных.
Когда вы загружаете объект свойств конфигурации либо из базы данных, либо из файла, полезно иметь его как синглтон; нет причин постоянно перечитывать статические данные, которые не изменятся во время работы сервера.
Общие ресурсы. Особенно в PHP - это класс базы данных, класс шаблона и класс хранилища глобальных переменных. Все они должны использоваться всеми модулями / классами, которые используются в коде.
Это истинное использование объекта -> класс шаблона содержит шаблон страницы, который создается, и он получает форму, добавляется, изменяется модулями, которые добавляются в вывод страницы. Чтобы это могло произойти, он должен храниться как единый экземпляр, и то же самое касается баз данных. С помощью синглтона общей базы данных все классы модулей могут получать доступ к запросам и получать их без необходимости их повторного запуска.
Одноэлементное хранилище глобальных переменных предоставляет вам глобальное, надежное и простое в использовании хранилище переменных. Это значительно упорядочивает ваш код. Представьте, что у вас есть все значения конфигурации в массиве в синглтоне, например:
$gb->config['hostname']
или имея все языковые значения в массиве, например:
$gb->lang['ENTER_USER']
В конце выполнения кода для страницы вы получите, скажем, уже зрелую версию:
$template
Синглтон, $gb синглтон, в котором есть массив lang для замены, а весь вывод загружен и готов. Вы просто заменяете их ключами, которые теперь присутствуют в значении страницы зрелого объекта шаблона, а затем передаете его пользователю.
Большим преимуществом этого является то, что вы можете выполнять ЛЮБУЮ постобработку, которая вам нравится, на чем угодно. Вы можете передать все языковые значения в Google Translate или другую службу перевода и получить их обратно, и заменить их на свои места, например переведенные. или вы можете заменить в структурах страниц или строках содержимого, как хотите.
Как все уже говорили, общий ресурс - а именно то, что не может обрабатывать одновременный доступ.
Один конкретный пример, который я видел, - это средство записи индекса поиска Lucene.
Вы можете использовать Singleton при реализации паттерна State (как показано в книге GoF). Это связано с тем, что конкретные классы State не имеют собственного состояния и выполняют свои действия в терминах класса контекста.
Вы также можете сделать Abstract Factory одноэлементным.
setState() ответственным за принятие решения о политике создания состояния. Это помогает, если ваш язык программирования поддерживает шаблоны или обобщения. Вместо синглтона вы можете использовать шаблон Monostate, где создание экземпляра объекта состояния заканчивается повторным использованием того же глобального / статического объекта состояния. Синтаксис для изменения состояния может остаться неизменным, поскольку вашим пользователям не нужно знать, что созданное состояние является моносостояниями.
- person Emile Cormier; 23.03.2017
Прежде всего, давайте различим одиночный объект и одиночный объект. Последнее является одной из многих возможных реализаций первого. И проблемы Единственного объекта отличаются от проблем Синглтона. Одиночные объекты не являются плохими по своей сути и иногда являются единственным способом сделать что-то. Суммируя:
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() и справиться со всеми проблемами многопоточности.
Еще раз: какой бы подход вы ни выбрали, вам придется заплатить цену одного объекта. Использование контейнера внедрения зависимостей просто переносит сложность на фреймворк, который должен будет справляться с проблемами, присущими отдельному объекту.
Резюме:
Я использую его для объекта, инкапсулирующего параметры командной строки при работе с подключаемыми модулями. Основная программа не знает, каковы параметры командной строки для загружаемых модулей (и даже не всегда знает, какие модули загружаются). например, основная загрузка A, которая сама по себе не нуждается в каких-либо параметрах (так почему он должен принимать дополнительный указатель / ссылку / что угодно, я не уверен - похоже на загрязнение), затем загружает модули X, Y и Z. Два из них, скажем, X и Z, нуждаются (или принимают) параметры, поэтому они обращаются к синглтону командной строки, чтобы сообщить ему, какие параметры принимать, а во время выполнения они перезванивают, чтобы узнать, действительно ли пользователь указал какие-либо из них.
Во многих отношениях синглтон для обработки параметров CGI будет работать аналогично, если вы используете только один процесс для каждого запроса (другие методы mod_ * этого не делают, поэтому там будет плохо - таким образом, аргумент, который говорит, что вы не должны: t используйте синглтоны в мире mod_cgi на случай, если вы переносите на mod_perl или в любой другой мир).
Может быть очень прагматично сконфигурировать определенные проблемы инфраструктуры как одиночные или глобальные переменные. Мой любимый пример - фреймворки внедрения зависимостей, в которых синглтоны используются в качестве точки подключения к фреймворку.
В этом случае вы полагаетесь на инфраструктуру, чтобы упростить использование библиотеки и избежать ненужной сложности.
Я думаю, если ваше приложение имеет несколько уровней, например, презентацию, домен и модель. Синглтон - хороший кандидат на роль сквозного слоя. И предоставлять услуги каждому уровню в системе.
По сути, Singleton обертывает сервис, например, такой как ведение журнала, аналитика, и предоставляет его другим уровням в системе.
И да, singleton должен следовать принципу единой ответственности.
Вы используете шаблон проектирования Singleton, когда хотите гарантировать, что у класса будет один экземпляр, и этот экземпляр будет иметь глобальную точку доступа к нему.
Допустим, у вас есть приложение, которому требуется база данных для обработки операций CRUD. В идеале вы должны использовать один и тот же объект подключения к базе данных для доступа к базе данных и выполнения операций CRUD.
Следовательно, чтобы гарантировать, что класс базы данных будет иметь один объект, и этот же объект будет использоваться во всем приложении, мы реализуем шаблон проектирования singleton.
Убедитесь, что ваш конструктор является частным и что вы предоставляете статический метод для предоставления доступа к единственному объекту одноэлементного класса.
Итак, я читаю о шаблоне синглтона для школы, и профессора составили список текущих мнений и лучших практик по этому вопросу. Кажется, есть согласие с идеей, что синглтон можно использовать, если вы построите его так, чтобы он ничего не добавлял в код. Если вы сделаете так, чтобы использование синглтона можно было включать и выключать буквально без каких-либо побочных эффектов, кроме рабочей нагрузки, то использование этого шаблона проектирования безопасно и желательно.
Возможно, пример с кодом.
Здесь ConcreteRegistry - это синглтон в игре в покер, который позволяет поведениям на всем пути вверх по дереву пакетов обращаться к немногим, основным интерфейсам игры (то есть фасадам для модели, представления, контроллера, среды и т. Д.):
http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html
Ed.