zoukankan      html  css  js  c++  java
  • 【设计模式】单例模式

    温故而知新,可以为师矣

    开场小故事

    “大鸟,今天我在公司写了一个窗体程序,当中有一个是‘工具箱’的窗体,问题就是我希望工具箱要么不出现,要么出现一个,可实际上我每单击菜单,实例化‘工具箱’,他就会出现一个,单击多次就会出现多个,你说怎么办?”

    “哈哈,显然你这个‘工具箱’类也要计划生育啊,不能让他超生了。这就是一个设计模式问题呀”

    ok,接下来我们就要讲讲这个设计模式---单例模式

    什么是单例模式?

    单例模式,保证一个类仅有一个实例,并提供一个访它的全局访问点。单例模式是对象创建型模式。

    这句话什么意思?就是说当我们对一个类进行实例化的时候,无论创建多少个对象,只会存在一个实例,至于什么是全局访问点,其实就是一个全局变量来保存一个对象。分析完成,我们通过代码来实现一下:

    不过在之前,假如你已经了解了python中__new____init__用途以及区别。

    class Singleton(object):
        _instance = None
    
        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = super().__new__(cls)
            return cls._instance
    
        def __init__(self):
            pass
    
    if __name__ == '__main__':
        singleton = Singleton()
        singleton2 = Singleton()
        print(id(singleton))  # 140668529220968
        print(id(singleton2))  # 140668529220968
    

    通过代码我们可以发现,在类中维持了一个_instance的类变量,它的作用就是保持单一实例,通过__new__魔法方法改变实例的生成过程。

    但是程序还是存在一个小问题,每当类调用一次__new__就是默认调用一次__init__,当调用多次,也会初始化多次。我们期望单例模式需要保证初始化工作只执行一次。接下来更改一下代码:

    class Singleton(object):
        _instance = None
        _init = True
    
        def __new__(cls, *args, **kwargs):
            if not cls._instance:
                cls._instance = super().__new__(cls)
            return cls._instance
    
        def __init__(self, name):
            if self._init:
                self._init = False
                self.name = name
    
    if __name__ == '__main__':
        singleton1 = Singleton("1")
        print(id(singleton1))
        singleton2 = Singleton("2")
        print(id(singleton2))
        print(singleton1.name) # 1
        print(singleton2.name) # 1
    

    代码改动很小,同样是利用一个私有类变量标记是否被__init__,这样当创建多个对象,还是传入不同是参数,有且仅有一个对象,也是第一次创建的那个对象。

    装饰器实现单例模式

    装饰器的形式也是通过改变类创建的过程,先看一下代码接着再来分析过程:

    from functools import wraps
    
    
    def single(cls):
        instance = dict()
    
        @wraps(cls)
        def wrapper(*args, **kwargs):
            if cls not in instance:
                instance[cls] = cls(*args, **kwargs)
            return instance[cls]
    
        return wrapper
    
    
    @single
    class Singleton(object):
        def __init__(self, name):
            self.name = name
    
    if __name__ == '__main__':
        singleton1 = Singleton("1")
        print(id(singleton1)) # 140130434647040
        singleton2 = Singleton("2")
        print(id(singleton2)) # 140130434647040
        print(singleton1.name) # 1
        print(singleton2.name) # 1
    

    代码发现我们实现了一个single的装饰器,存在一个局部变量instance,其装饰器的主要过程:

    1. @single相当于Singleton = single(Singleton)
    2. 装饰完成,执行创建对象,single函数会返回一个wrapper内部函数名,此时Singleton = wrapper,而我们自己调用的Singleton("1"),就相当于wrapper("1")
    3. 调用wrapper函数会判断步骤一传入的参数是否存在于instance(这是单例模式的关键),不存在,说明是第一次调用,此时执行的cls(*args,**kwargs),才是真正去执行Singleton("1"),这个类也就会调用__init__,整个对象创建完成,然后返回。
    4. 当下一次继续创建对象的时候,会判断instance存不存在该对象的类,存在这直接返回该类的对象。
  • 相关阅读:
    MyBatis Generator自动生成MyBatis的映射代码
    ajax 文件上传,ajax
    【学生必备求职指南】好简历是怎样炼成的?毕业生简历实例点评版 转载
    FC8下备份linux系统
    Fedora 18 安装前指南
    Fedora 18安装Google输入法和云拼音
    mfc radio group 设置
    MySQL Server 安装
    【转载】COM组件设计与应用(四)——简单调用组件
    【转载】COM组件设计与应用(三)——数据类型
  • 原文地址:https://www.cnblogs.com/ydongy/p/13062985.html
Copyright © 2011-2022 走看看