Шаблоны проектирования Python — шаблон Singleton

задняя часть Python GitHub Шаблоны проектирования

问题:Современные шоколадные фабрики имеют шоколадные котлы с компьютерным управлением. Что делает котел, так это плавит шоколад и молоко вместе и отправляет их на следующую стадию для изготовления шоколадных батончиков. Ниже приведен код контроллера котла шоколадной компании, посмотрите внимательнее, что не так с этим кодом?

class ChocolateBoiler(object):

    def __init__(self):
        self.empty = True
        self.boiled = False

    def fill(self):
        # 向锅炉填充巧克力和牛奶混合物
        # 在锅炉内填充原料时,锅炉必须是空的。
        # 一旦填入原料,就要把empty 和 boiled 标志设置好
        if self.empty:
            self.empty = False
            self.boiled = False

    def drain(self):
        # 排出煮沸的巧克力和牛奶
        # 锅炉排出时,必须是满的且煮沸的。
        # 排出完毕empty 设置为 true
        if not self.empty and self.boiled:
            self.empty = True

    def boil(self):
        # 将颅内物煮沸
        # 煮混合物时,锅炉内必须是满的且没有煮沸过
        # 一旦煮沸,就把 boiled 设置为 true
        if not self.empty and not self.boiled:
            self.boiled = True

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

_chocolate_boiler_instance = None  # 声明实例

def chocolate_boiler():
    global _chocolate_boiler_instance  # 使用全局变量

    if _chocolate_boiler_instance is not None: # 判断是否存在,如果存在,直接返回
        return _chocolate_boiler_instance
    else:
        # 如果不存在,创建一个新的
        _chocolate_boiler_instance = ChocolateBoiler()
        return _chocolate_boiler_instance

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

эта гарантияChocolateBoilerШаблон, который имеет только один экземпляр класса и предоставляет глобальную точку доступа, т.单例模式.

одноэлементный шаблон

определение

单例模式:Убедитесь, что существует только один экземпляр класса, и предоставьте глобальную точку доступа.

  • Другими словами, мы используем шаблон singleton для разработки класса как отдельного экземпляра, управляемого самим собой, и в то же время избегаем того, чтобы другие классы генерировали экземпляры сами по себе. И получить экземпляр синглтона можно только через класс синглтона.
  • Мы также предоставляем глобальную точку доступа к этому экземпляру: когда вам нужен экземпляр, например запрос класса, он возвращает один экземпляр.

выполнить

Есть несколько вариантов реализации рисунка Singleton в Python:

использовать метакласс

"поваренная книга Python" предоставляет очень простой в использованииSingletonКласс, пока он наследуется от него, становится синглтоном.

# python 3 代码实现
class Singleton(type):

    def __init__(self, *args, **kwargs):
        self.__instance = None
        super().__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            # 如果 __instance 不存在,创建新的实例
            self.__instance = super().__call__(*args, **kwargs)
            return self.__instance
        else:
            # 如果存在,直接返回
            return self.__instance


class Spam(metaclass=Singleton):

    def __init__(self):
        print('Creating Spam')

a = Spam()
b = Spam()

print(a is b)  # 这里输出为 True

Метакласс (metaclass) может управлять процессом создания класса, в основном он делает три вещи:

  • Создание класса перехвата
  • Изменить определение класса
  • Возвращает измененный класс

В примере мы создаем метакласс Singleton и используемcallМетоды позволяют моделировать поведение функции. Когда создается класс Spam, его метакласс устанавливается в Singleton, затем при создании объекта класса Spam поведение происходит следующим образом:

Spam = Singleton(name, bases, class_dict), Спам на самом деле является экземпляром класса Singleton.

При создании экземпляра Spam Spam()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).call(), который указывает всем экземплярам спама атрибут __instance спама.

использоватьnew

мы можем использоватьnewДля управления процессом создания экземпляра используется следующий код:

class Singleton(object):

    __instance = None

    def __new__(cls, *args, **kw):
        if not cls.__instance:
            cls.__instance = super().__new__(cls, *args, **kw)
        return cls.__instance

class Foo(Singleton):
    a = 1

one = Foo()
two = Foo()
assert one == two
assert one is two
assert id(one) == id(two)

пройти черезnewметод, который привязывает экземпляр класса к свойству класса при его созданииэкземпляр на. если клс.instance имеет значение None, что указывает на то, что экземпляр класса не был создан, создайте экземпляр и привяжите экземпляр к cls.instance возвращает экземпляр, созданный первым экземпляром, каждый раз, когда он создается. Будьте осторожны, чтобы не перегружаться при создании подклассов Singleton.новый__.

Используйте декоратор

import functools

def singleton(cls):
    ''' Use class as singleton. '''
    # 首先将 __new__ 方法赋值给 __new_original__
    cls.__new_original__ = cls.__new__

    @functools.wraps(cls.__new__)
    def singleton_new(cls, *args, **kw):
        # 尝试从 __dict__ 取 __it__
        it =  cls.__dict__.get('__it__')
        if it is not None: # 如果有值,说明实例已经创建,返回实例
            return it
        # 如果实例不存在,使用 __new_original__ 创建实例,并将实例赋值给 __it__
        cls.__it__ = it = cls.__new_original__(cls, *args, **kw)
        it.__init_original__(*args, **kw)
        return it
    # class 将原有__new__ 方法用 singleton_new 替换
    cls.__new__ = singleton_new
    cls.__init_original__ = cls.__init__
    cls.__init__ = object.__init__

    return cls

#
# 使用示例
#
@singleton
class Foo:
    def __new__(cls):
        cls.x = 10
        return object.__new__(cls)

    def __init__(self):
        assert self.x == 10
        self.x = 15


assert Foo().x == 15
Foo().x = 20
assert Foo().x == 20

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

  • Во-первых, поставитьnewметод, назначенныйnew_original,оригиналnewЗамена метода на Singleton_Newinit_originalи установить клс.initназначить наinit_original
  • Внутри метода singleton_new попробуйте начать сdictВыбиратьit(пример)
  • Если экземпляр не существует, используйтеnew_originalСоздайте экземпляр и назначьте экземплярit, затем верните экземпляр

самый простой способ

Привяжите имя singleton к экземпляру, и singleton станет единственным объектом своего собственного класса.

class singleton(object):
    pass
singleton = singleton()

GitHub.com/cousby/me упоминает…Это способ получить глобальный запрос

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

Ссылка на ссылку


Наконец, поблагодарите мою подругу за ее поддержку.

Добро пожаловать в подписку (April_Louisa) купи мне фанту
欢迎关注
Добро пожаловать, чтобы следовать
请我喝芬达
купи мне фанту