Реализация шаблона синглтона в Python
http-equiv=»Content-Type» content=»text/html;charset=UTF-8″>style=»clear:both;»>
В Python мы можем реализовать шаблон синглтона несколькими способами:
Используйте модули usenew Использовать декоратор Использовать метакласс (metaclass) Использовать модуль
1. Фактически, модули Python являются естественным одноэлементным режимом, потому что, когда модуль импортируется в первый раз, он генерирует файл .pyc, а когда он импортируется во второй раз, он непосредственно загружает файл .pyc без повторного выполнения модуля. код. Поэтому нам нужно только определить связанные функции и данные в модуле, чтобы получить одноэлементный объект. Если нам действительно нужен одноэлементный класс, мы можем рассмотреть возможность сделать это:
Во-вторых, метод статических переменных Метод класса __new__ выполняется первым (когда мы не написали, объект вызывается по умолчанию.new), Создайте экземпляр объекта, затем выполните метод класса __init__ для инициализации объекта, чтобы мы могли реализовать одноэлементный режим на основе этого.
В приведенном выше коде мы связываем экземпляр класса с переменной класса _instance. Если cls._instance имеет значение None, создайте экземпляр, в противном случае непосредственно верните cls._instance.
Три, мета-класс метод Принцип: метод __new__ и метод __init__ метакласса метакласса используются для создания объектов класса,call Метод используется для управления экземпляром экземпляра объекта, то есть объектом класса. Метод __call__ вызывает метод __new__ класса экземпляра, который используется для создания объектов. Верните объект в метод __call__, а затем вызовите метод __init__ объекта класса для инициализации объекта. Метакласс может управлять процессом создания класса. Он в основном выполняет три функции: создание класса перехвата Изменить определение класса Вернуться к измененному классу
4. Декоратор Принцип: декоратор используется для управления классом для вызова метода __call__. Декоратор может динамически изменять функцию класса или функции. Здесь мы также можем использовать декоратор для украшения класса, чтобы он мог генерировать только один экземпляр, код выглядит следующим образом:
Выше мы определили синглтон-декоратор, который возвращает внутреннюю функцию getinstance, функция будет определять, есть ли класс в экземплярах словаря, если он не существует, она будет использовать cls в качестве ключа, cls (* args, ** kw) хранится в экземплярах как значение, в противном случае возвращает экземпляры напрямую.
Интеллектуальная рекомендация
19.03.21 Я загрузил комплексные обучающие видеоуроки Photoshop CC 2015 и обучающие видеоуроки по новым функциям PS CC 2015. Я просмотрел несколько видео, но мне кажется, что они в основном объясняют н…
…
проверка данных весеннего mvc Два способа проверки данных Spring MVC: 1.JSR303 2.Hibernate Validator Второй метод является дополнением к первому методу Шаги для проверки данных с использованием Hibern…
Существует два способа вызова между сервисами Springcloud: RestTemplate и Feign. Здесь мы представляем сервисы вызова RestTemplate. 1. Что такое RestTemplate RestTemplate — это структура веб-запросов …
1. Понимать предварительный, средний, последующий порядок и иерархическую последовательность бинарных деревьев; Свяжите язык C со структурой данных двоичного дерева; Освойте с…
Вам также может понравиться
Последнее обучение, как использовать Kaldi, чтобы проснуться без использования WSTF, поэтому вам нужно глубоко пойти в Kaldi для обучения. Временное состояние обучения. Три изображения представляют со…
Во время простоя некоторые веб-страницы, которые мы создали, не были завершены, но не хотят, чтобы другие видели, вы можете создать простой эффект шифрования страницы на странице этой веб-страницы, ан…
Расширенные статьи серии Zookeeper 1. NIO, ZAB соглашение, 2PC представления концепции 2. Лидер выборов 3. Рукописный распределенный замок, центр настройки ==================================== 1. NIO,…
Посмотрите на конечный эффект первым DemoPreview.gif SETP1 эффект капли воды Первая реакция на эффект капли воды — нарисовать замкнутую кривую. С помощью события MotionEvent измените радиус во время п…
…
Что такое метакласс в Python?
Метапрограммирование в Python полагается на специальный новый тип класса, который называется метаклассом. Короче говоря, этот тип класса содержит инструкции о скрытой генерации кода, которую вы хотите выполнять, когда выполняется другой фрагмент кода.
Википедия довольно хорошо резюмирует метаклассы. В объектно-ориентированном программировании метакласс – это класс, экземпляры которого являются классами. Когда мы определяем его, объекты создаются с использованием этого класса в качестве чертежа.
А как насчет самого класса? Каков план самого класса? Здесь на помощь приходит метакласс. Метакласс – это проект самого класса, точно так же, как он является планом экземпляров этого класса. Метакласс – это класс, который определяет свойства других классов.
С помощью метакласса мы можем определять свойства, которые следует добавлять в новые классы, определенные в нашем коде.
Например, следующий пример кода метакласса добавляет свойство hello к каждому классу, который использует этот метакласс в качестве своего шаблона. Это означает, что новые классы, являющиеся экземплярами этого метакласса, будут иметь свойство hello без необходимости определять его.
# hello_metaclass.py # A simple metaclass # This metaclass adds a 'hello' method to classes that use the metaclass # meaning, those classes get a 'hello' method with no extra effort # the metaclass takes care of the code generation for us class HelloMeta(type): # A hello method def hello(cls): print("greetings from %s, a HelloMeta type class" % (type(cls()))) # Call the metaclass def __call__(self, *args, **kwargs): # create the new class as normal cls = type.__call__(self, *args) # define a new hello method for each of these classes setattr(cls, "hello", self.hello) # return the class return cls # Try out the metaclass class TryHello(object, metaclass=HelloMeta): def greet(self): self.hello() # Create an instance of the metaclass. It should automatically have a hello method # even though one is not defined manually in the class # in other words, it is added for us by the metaclass greeter = TryHello() greeter.greet()
Результатом выполнения этого кода является то, что новый класс TryHello может распечатать приветствие, в котором говорится:
greetings from <class '__main__.TryHello'>, a HelloMeta type class
Метод, ответственный за эту распечатку, не указан в объявлении класса. Скорее, метакласс, которым в данном случае является HelloMeta, генерирует код во время выполнения, который автоматически прикрепляет метод к классу.
Чтобы увидеть это в действии, скопируйте и вставьте код в консоль Python. Также прочтите комментарии, чтобы лучше понять, что мы сделали в каждой части кода. У нас есть новый объект с именем greeter, который является экземпляром класса TryHello. Однако мы можем вызвать метод TryHello self.hello, даже если такой метод не был определен в объявлении класса.
Вместо того, чтобы получать ошибку при вызове несуществующего метода, TryHello получает такой метод, автоматически прикрепленный к нему из-за использования класса HelloMeta в качестве своего метакласса.
Метаклассы дают нам возможность писать код, который преобразует не только данные, но и другой код, например, преобразует класс во время его создания. В приведенном выше примере наш метакласс автоматически добавляет новый метод к новым классам, которые мы определяем для использования в качестве своего метакласса.
Это пример метапрограммирования. Метапрограммирование – это просто написание кода, который работает с метаклассами и связанными с ними методами для выполнения некоторой формы преобразования кода в фоновом режиме.
Самое прекрасное в метапрограммировании заключается в том, что вместо вывода исходного кода оно возвращает нам только выполнение этого кода. Конечный пользователь нашей программы не подозревает о «magic», происходящем в фоновом режиме.
Подумайте о программных фреймворках, которые генерируют код в фоновом режиме, чтобы вам, как программисту, приходилось писать меньше кода для всего. Вот несколько отличных примеров:
- Django;
- SQLAlchemy;
- Flask;
- Theano.
Помимо Python, другие популярные библиотеки, такие как Ruby On Rails (Ruby) и Boost (C++), являются примерами того, где метапрограммирование используется авторами фреймворка для генерации кода и заботы о вещах в фоновом режиме.
Результатом являются упрощенные API для конечных пользователей, которые автоматизируют большую часть работы программиста, который кодирует во фреймворке.
Забота о том, чтобы эта простота работала за кулисами, заключается в большом количестве метапрограммирования, встроенном в исходный код фреймворка.
Работа с классами на Python
Большая часть времени работы программиста — это работа с классами и их экземплярами. Изменим наш предыдущий класс и добавим дополнительные атрибуты, которые сможем в последующем менять при работе с экземплярами класса.
class Car():
«»»Описание автомобиля»»»
def __init__(self, brand, model, years):
«»»Инициализирует атрибуты»»»
self.brand = brand
self.model = model
self.years = years
self.mileage = 0
def get_full_name(self):
«»»Автомобиль»»»
name = «Автомобиль {self.brand} {self.model} {self.years}»
name.
def read_mileage(self):
«»»Пробег автомобиля»»»
(«Пробег автомобиля {self.mileage} км.»)
В описание автомобиля есть три атрибута(параметра) это brand, model, years. Также мы создали новый атрибут mileage (пробег) и присвоили ему начальное значение 0. Так как пробег у всех автомобилей разный, в последующем мы сможем изменять этот атрибут. Метод get_full_name будет возвращать полное описание автомобиля. Метод read_mileage будет выводить пробег автомобиля.
Создадим экземпляр с классом Car и запустим методы:
car_2 = Car(‘audi’, ‘a4’, 2019)
print(car_2.get_full_name())
car_2.read_mileage()
В результате в начале Python вызывает метот __init__() для создания нового экземпляра. Сохраняет название, модель, год выпуска и создает новый атрибут с пробегом равным 0. В итоге мы получим такой результат:
Автомобиль Audi A4 2019
Пробег автомобиля 0 км.
2.1. Прямое изменение значения атрибута
Для изменения значения атрибута можно обратиться к нему напрямую и присвоить ему новое значение. Изменим пробег автомобиля car_2:
car_2 = Car(‘audi’, ‘a4’, 2019)
print(car_2.get_full_name())
car_2.mileage = 38
car_2.read_mileage()
Мы обратились к нашему экземпляру car_2 и связанным с ним атрибутом пробега(mileage) и присвоили новое значение 38. Затем вызвали метод read_mileage() для проверки. В результате мы получим следующие данные.
Автомобиль Audi A4 2019
Пробег автомобиля 38 км.
2.2. Изменение значения атрибута с использованием метода
В Python удобнее писать методы, которые будут изменять атрибуты за вас. Для этого вы просто передаете новое значение методу, который обновит значения. Добавим в наш класс метод который будет изменять показания пробега.
class Car():
«»»Описание автомобиля»»»
def __init__(self, brand, model, years):
«»»Инициализирует атрибуты»»»
self.brand = brand
self.model = model
self.years = years
self.mileage = 0
def get_full_name(self):
«»»Автомобиль»»»
name = «Автомобиль {self.brand} {self.model} {self.years}»
name.
def read_mileage(self):
«»»Пробег автомобиля»»»
(«Пробег автомобиля {self.mileage} км.»)
def update_mileage(self, new_mileage):
«»»Устанавливает новое значение пробега»»»
self.mileage = new_mileage
car_2 = Car(‘audi’, ‘a4’, 2019)
print(car_2.get_full_name())
car_2.read_mileage()
car_2.update_mileage(17100)
car_2.read_mileage()
Вначале выведем текущие показания пробега ( car_2.read_mileage() ). Затем вызовем метод и передадим ему новое значение пробега ( car_2.update_mileage(17100) ). Этот метод устанавливает пробег 17100. Выведем текущие показания ( car_2.read_mileage() ) и у нас получается:
Автомобиль Audi A4 2019
Пробег автомобиля 0 км.
Пробег автомобиля 17100 км.
2.3. Изменение значения атрибута с приращением
Если вместо того, чтобы присвоить новое значение, требуется изменить с значение с приращением, то в этом случаем мы можем написать еще один метод, который будет просто прибавлять пробег к уже имеющемся показаниям. Для этого добавим метод add_mileage в класс :
def add_mileage(self, km):
«»»Добавляет пробег»»»
self.mileage += km
Новый метод add_mileage() получает пробег в км и добавлет его к self.mileage.
car_2.add_mileage(14687)
car_2.()
Пробег автомобиля 31787 км.
В итоге после вызова метода add_mileage() пробег автомобиля в экземпляре увеличится на 14687 км и станет равным 31787 км. Данный метод мы можем вызывать каждый раз при изменении пробега и передавать новые значение, на которое будет увеличивать основной пробег.
Всегда думайте перед созданием Синглтона
Заманчиво иметь некий объект, доступный в любой точке программы. Но это нарушает многие принципы создания хорошего кода. Поэтому не спешите добавлять Синглтоны, которые усложняют логику программы и вносят лишние зависимости.
Рассмотрим пример. Может показаться хорошей идеей создать класс для управления настройками приложения в виде Синглтона. Тогда все компоненты приложения смогут видеть необходимые опции и легко их использовать. С одной стороны, идея кажется довольно неплохой. Конфигурация приложения действительно может быть представлена уникальной сущностью. А свободный доступ к Синглтону упростит использование конфигурации.
Однако в этом случае появляется серьезная проблема. Все компоненты начинают зависеть от Синглтона. Если понадобится перенести только один из классов в другое приложение, то придется тащить вместе с ним и Синглтон, который может быть предназначен для управления параметрами десятков других классов. Лучше потратить немного больше времени на проектирование, но обеспечить четкую передачу параметров в классы через их конструкторы, а не через незаметный Синглтон.
К тому же, паттерн Синглтон усложняет использование полиморфизма и других прелестей ООП, которые могут понадобится, когда уже минимальным рефакторингом обойтись не удастся.
Хотя есть и вполне безобидные применения Синглтонов. Например, при реализации другого паттерна: Абстрактная Фабрика.
Также использование Синглтона оправдано для представления физически уникальных ресурсов компьютера. Например, систему слежения за подключением/отключением USB-устройств уместно реализовать в виде Синглтона.
Возможные проблемы, чтобы рассмотреть
Инструменты для людей, которые знают, как их использовать. Несмотря на все плохие вещи, написанные о Singletons, люди все еще используют их, потому что:
- Они наполняют необходимость лучше, чем альтернативы.
и/или
- Они не знают лучше, и они создают проблемы в своем коде, используя их.
Избегайте проблем. Не будь в группе 2.
Проблемы с Singletons вызваны, потому что они нарушают правило на одну ответственность. Они делают три вещи:
- Гарантия только один экземпляр существует
- Предоставить глобальный доступ к этому экземпляру
- Предоставить свою собственную бизнес-логику.
- Потому что они нарушают правило на одну ответственность, синглтоны могут быть трудно проверить
- Singletons могут привести к крепко Советный код Отказ Глобальный экземпляр, который имеет непостоянное состояние, может потребовать от объекта, чтобы зависеть от состояния глобального объекта.
- Это директор OO для Отдельная творческая логика из бизнес-логики Отказ Придерживаясь этого принципа «Singletons Должны никогда не будешь использовать». Снова со словом следует. Вместо этого, будь Йода: « сделать или нет! ». Основание решения по вашему собственному коду.
- Память, выделенная синглтоном, не может быть освобождена. Это только проблема, которую необходимо освободить память.
Создание синглета в Python (13)
Этот вопрос заключается не в обсуждении того, желателен ли шаблон однократной конструкции , либо в виде анти-шаблона, либо для любых религиозных войн, но для обсуждения того, как этот шаблон лучше всего реализован на Python таким образом, который является наиболее pythonic. В этом случае я определяю «самый пифонический», чтобы означать, что он следует «принципу наименьшего удивления» .
У меня есть несколько классов, которые станут синглонами (мой вариант использования для регистратора, но это не важно). Я не хочу загромождать несколько классов с добавленным gumph, когда я могу просто наследовать или украшать
Лучшие методы:
Отложенный экземпляр в Singleton
Одним из вариантов использования шаблона Singleton является отложенная инициализация. Например, в случае импорта модулей мы можем автоматически создать объект, даже если он не нужен. Отложенное создание экземпляра гарантирует, что объект создается, только тогда, когда он действительно необходим. В следующем примере кода, когда мы используем s = Singleton(), вызывается метод __init__, но при этом новый объект не будет создан. Фактическое создание объекта произойдет, когда мы используем Singleton.getInstance().
class Singleton: __instance = None def __init__(self): if not Singleton.__instance: print(" __init__ method called..") else: print("Instance already created:", self.getInstance()) @classmethod def getInstance(cls): if not cls.__instance: cls.__instance = Singleton() return cls.__instance s = Singleton() ## class initialized, but object not created print("Object created", Singleton.getInstance()) # Object gets created here s1 = Singleton() ## instance already created
Способ 2: декоратор
def singleton(Cls): singletons = {} def getinstance(*args, **kwargs): if Cls not in singletons: singletons = Cls(*args, **kwargs) return singletons return getinstance @singleton class MyClass: def __init__(self): self.val = 3 x = MyClass() y = MyClass() x.val = 42 x is y, y.val, type(MyClass)
Плюс
- Код для записи декоратора отдельно от создания класса.
- Это можно повторно использовать как можно больше синглтонов, сколько вам нужно.
- Синглтон декоратор отмечает намерение, которое ясно и понятно
Господин
-
Звонок будет разрешаться как Функция Отказ
Создание метода класса в MyClass приведет к ошибке синтаксиса.
Если вы действительно хотите использовать декоратор и должны сохранить определение класса, есть способ. Вы можете использовать эту библиотеку:
pip install singleton_decorator
Библиотека обертывания и переисканы класс Singleton. Поочередно вы можете написать свой собственный. Вот реализация:
def singleton(Cls): class Decorated(Cls): def __init__(self, *args, **kwargs): if hasattr(Cls, '__init__'): Cls.__init__(self, *args, **kwargs) def __repr__(self) : return Cls.__name__ + " obj" __str__ = __repr__ Decorated.__name__ = Cls.__name__ class ClassObject: def __init__(cls): cls.instance = None def __repr__(cls): return Cls.__name__ __str__ = __repr__ def __call__(cls, *args, **kwargs): if not cls.instance: cls.instance = Decorated(*args, **kwargs) return cls.instance return ClassObject() @singleton class MyClass(): pass x = MyClass() y = MyClass() x.val = 42 x is y, y.val
Вывод:
(True, 42)
Интерактивное упражнение : Запустите следующую интерактивную визуализацию памяти. Сколько экземпляров Singleton вы найдете?
Использовать метакласс
Я бы рекомендовал метод #2 , но вам лучше использовать метакласс , чем базовый класс. Вот пример реализации:
Или в Python3
Если вы хотите запускать каждый раз, когда вызывается класс, добавьте
к заявлению в .
Несколько слов о метаклассах. Метакласс-это класс класса, то есть класс-это экземпляр его метакласса . Вы находите метакласс объекта в Python с . Обычные классы нового стиля относятся к типу . в приведенном выше коде будет иметь тип , так же как (единственный) экземпляр будет иметь тип . Когда вы вызываете logger с , Python сначала спрашивает метакласс , , что делать, позволяя упреждать создание экземпляра. Этот процесс аналогичен тому, как Python спрашивает класс, что делать, вызывая , когда вы ссылаетесь на один из его атрибутов, делая .
Метакласс по существу решает, что означает определение класса и как реализовать это определение. См., например , http://code.activestate.com/recipes/498149/ , который по существу воссоздает C-style s в Python с использованием метаклассов. Нить Каковы некоторые (конкретные) варианты использования метаклассов? также приводится несколько примеров, они обычно кажутся связанными с декларативным программированием, особенно используемым в ORMs.
В этой ситуации, если вы используете свой метод #2 , а подкласс определяет метод , он будет выполняться каждый раз , когда вы вызываете , потому что он отвечает за вызов метода, возвращающего сохраненный экземпляр. В случае метакласса он будет вызван только один раз, когда будет создан единственный экземпляр. Вы хотите настроить то , что означает вызов класса, который определяется его типом.
В общем, имеет смысл использовать метакласс для реализации singleton. A singleton является особенным , потому что создается только один раз, а метакласс-это способ настройки создания класса . Использование метакласса дает вам больше контроля в случае, если вам нужно настроить определения класса singleton другими способами.
Ваши синглеты не будут нуждаться в множественном наследовании (поскольку метакласс не является базовым классом), но для подклассов созданного класса , использующих множественное наследование, вам нужно убедиться, что класс singleton является первым / крайним левым классом с метаклассом, который переопределяет , это очень маловероятно. Экземпляр dict не находится в пространстве имен экземпляра , поэтому он не будет случайно перезаписывать его.
Вы также услышите, что шаблон singleton нарушает ответственность «Single Principle»-каждый класс должен делать только одну вещь . Таким образом, вам не нужно беспокоиться о том, чтобы испортить одну вещь, которую код делает, если вам нужно изменить другую, потому что они разделены и инкапсулированы. Реализация метакласса проходит этот тест . Метакласс отвечает за соблюдение шаблона , и созданный класс и подклассы не должны знать, что они являются синглетами . Метод #1 не проходит этот тест, как вы заметили с помощью «MyClass, сам по себе является функцией, а не классом, поэтому вы не можете вызывать методы класса из него.»
Python 2 и 3 совместимые версии
Написание чего-то, что работает как в Python2, так и в python3, требует использования несколько более сложной схемы. Поскольку метаклассы обычно являются подклассами типа , можно использовать один из них для динамического создания промежуточного базового класса во время выполнения с ним в качестве своего метакласса, а затем использовать его в качестве базового класса открытого базового класса . Это труднее объяснить, чем сделать, как показано ниже:
Ирония этого подхода заключается в том, что он использует подклассы для реализации метакласса. Одно из возможных преимуществ состоит в том, что, в отличие от чистого метакласса, вернет .
Дальнейшее изучение
- Брэндон Родос, Синглтон шаблон
- Мишко Хревери, Singleton Я люблю тебя – но вы приносите меня Отказ Отказался от комментариев
- Мишко Хревери, Singletons являются патологическими лжецами
- Мишко Хревери, Где у всех синглтонов ушли
- Википедия Singleton_Pattern.
- Майкл Сафаян, Singleton Anti-Pattern
- Марк Радфорд Singleton, антизаблоки
- Алекс Миллер, Узоры я ненавижу # 1: Singleton
-
Скотта Денсмора/Брайан, Почему одиноки злые
Мартин Брэмптон, Хорошо использованные синглтоны хороши!
- Обсуждение, отредактированное Cunningham & Cunningham, Синглтон Глобальные проблемы
- Роберт Нистрем, Дизайн шаблонов пересматривается: Singleton
- Стив Егге, Singleton считается глупо
- J.b. жгнбергер Используйте свои синглтоны с умом
Мета-ноты – Мишко Хревери.
Хевери работал в Google, когда он написал эти блоги. Его блоги были читаемыми, развлекательными, информативными, провокационными и вообще завышенными, чтобы сделать точку зрения. Если вы читаете его блоги, обязательно прочитайте комментарии. Singletons являются патологическими лжецами Имеет пример тестирования подразделения, который иллюстрирует, как Singletons могут затруднить выяснение цепей зависимости и запуск или тестирование приложения. Это довольно крайний пример злоупотребления, но он делает действительный смысл:
Singletons – не что иное, как глобальное государство. Глобальное состояние делает его, чтобы ваши объекты могли тайно получить вещи, которые не объявлены в их API, а в результате Singletons делают ваши API в патологические лжецы.
Конечно, он немного преувеличивает. Singletons обертывают глобальное состояние в классе и используются для вещей, которые являются «естественными» глобальными по природе. Как правило, hevery рекомендует инъекцию зависимостей для замены синглтонов. Это просто означает объекты, передают свои зависимости в их конструкторе.
Где у всех синглтонов ушли Делает то, что инъекция зависимостей позволила легко получить экземпляры для конструкторов, которые требуют их, что облегчает лечебную потребность позади плохих, глобальных синглтонов в патологических лжецах.
Meta Notes – Брэндон Родос Синглтон Узор
Python Programmers почти никогда не реализуют шаблон Singleton, как описано в банде из четырех книг, чья Singleton Class запрещает нормальное зрелище и вместо этого предлагает метод класса, который возвращает экземпляр Singleton. Python более элегантный, и позволяет классу продолжать поддерживать нормальный синтаксис для создания института при определении пользовательских Метод, который возвращает экземпляр Singleton. Но еще более Pythonic подход, если ваш дизайн заставляет вас предлагать глобальный доступ к объекту Singleton, вместо этого используется глобальный шаблон объекта.
Meta Notes – J.B. Rainsberger Удивительно используют свои синглеты
Знать, когда использовать синглтоны, и когда оставить их позади
J.B. Rainsberger
Опубликовано 01 июля 2001 года 2001 г. Автоматизированное тестирование подразделения наиболее эффективно, когда:
- Связь между классами только так же сильна, как это должно быть
- Просто использовать MOCK Реализации сотрудничающих классов вместо реализации производства
Singletons знают слишком много
Существует одна реализация анти-образца, которая процветает в приложении с слишком многими синглетами: я знаю, где вы живете анти-образцом. Это происходит, когда, среди сотрудников классов совместных сотрудников, один класс знает, где получить экземпляры другого.
К приемлемым синглторам
Можно избежать злоупотребления синглтоном, глядя на проблему с другого угла. Предположим, что приложение необходимо только один экземпляр класса, а приложение настраивает этот класс при запуске: почему сам класс не отвечает за то, что он является синглтоном? Это кажется довольно логичным для приложения, чтобы принять эту ответственность, поскольку приложение требует такого поведения. Применение, а не компонент, должен быть синглтоном. Затем приложение делает экземпляр компонента, доступный для любого кода, специфичного приложения для использования. Когда приложение использует несколько таких компонентов, он может согревать их в то, что мы назвали инструментов.
Вместо того, чтобы использовать этот шаблон, просто создайте единый экземпляр и распространяйте его на места, которые используют объект в качестве параметра, чтобы сделать зависимость явной.