Почему Синглтон?
Важность очевидна, в наших проектах часто требуется «глобальная переменная процесса (блок памяти)», а одноэлементный шаблон является самым простым из нескольких шаблонов проектирования.
Ленивая и полезная практика: константы на уровне модуля
Я часто использую этот способ, потому что он прост и менее подвержен ошибкам.
Как мы все знаем, модульная концепция Python — это естественный синглтон. И Python — это язык с несколькими парадигмами, вам не нужно использовать класс для обработки этого, как в Java, это естественная идея — определить константу на уровне модуля.
код показывает, как показано ниже:
- Определяется
singleton.py
class _MySingleton(object):
"""
我们使用下划线开头, 告诫调用者, 不要直接 new
也不要来访问这个class
"""
def __init__(self, name, age):
self._name = name
self._age = age
def print_name(self):
print(self._name)
# 可以定制多个全局实例
S1 = _MySingleton('s1', 22)
S2 = _MySingleton('s2', 11)
- абонент
caller.py
from singleton import S1
# 尽情使用S1( 在任意点import 都可以 ), 它是全局唯一的!
Формальная практика: метапрограммирование
Некоторым людям не нравится описанный выше подход, они думают, что он «разрушает чистоту кода».В настоящее время мы можем использовать метод метапрограммирования, чтобы приблизиться на один шаг.
Это код, взятый из кулинарной книги Python.
- базовый класс метакласса
class SingletonMetaclass(type):
def __init__(self, *args, **kwargs):
self.__instance = None
super().__init__(*args, **kwargs)
def __call__(self, *args, **kwargs):
if self.__instance is None:
self.__instance = super(SingletonMetaclass, self).__call__(*args, **kwargs)
return self.__instance
else:
return self.__instance
- Класс, наследующий базовый класс метакласса
class SpamSingleton(metaclass=SingletonMetaclass):
"""注意: 根据Singleton的定义, 构造函数一般需要使用默认的构造函数"""
def get_addr(self):
return id(self)
- абонент
from singleton import SpamSingleton
s1 = SpamSingleton()
s2 = SpamSingleton()
pritn(id(s1), id(s2)) # 内存地址是一样的
Честно говоря, до сих пор немного сложно понять рабочий процесс SingletonMetaclass, я долго разбирался с процессом вызова вышеперечисленных методов.
Однако роль SingletonMetaclass тоже огромна. Мы определяем и помещаем его в файл base.py. В любое время, когда мы хотим определить класс Singleton, мы можем напрямую наследовать от него, что просто и удобно.
Сравнение подхода Хака: шаблон Борга
Излишне говорить, что все результаты, найденные поисковыми системами, рекомендуют эту практику, что заставляет людей думать, что это «мейнстримная практика» (на самом деле это не так).
Этот подход изменяет определение синглтона, то есть: все переменные совместно используют блок памяти, но содержимое этого блока памяти можно изменить. Затем, поместив экземпляр__dict__класс перенаправления метода__dict__метод достижения своей цели.
Но такой подход не очень соответствует моему восприятию Синглтона, то есть глобально уникален, и его содержимое не должно меняться. Так что в реальной разработке мне не нравится такой подход.
Сделайте еще один шаг вперед
Вообще говоря, лучший подход состоит в том, чтобы внедрить Manager вне кода приложения и позволить ему создавать синглтоны и управлять ими для нас. Эта практика также очень распространена, это то, что мы обычно называем «инфраструктурой внедрения зависимостей».
Если вы используете Spring, все прекрасно; если вы не используете Spring, я часто использую Guice для своей инфраструктуры внедрения зависимостей.
Тем не менее, сообщество Python, похоже, не очень заинтересовано в «инфраструктуре внедрения зависимостей», «контейнере IoC» и т. д. (на самом деле хорошие вещи), поэтому я не буду упоминать об этом здесь.
Суммировать
С личной точки зрения я предпочитаю точку зрения «Освоить один или два метода, а затем использовать наиболее искусный и правильный», поэтому рекомендую только первый и второй методы.