单例模式

定义

有且只有一个对象被创建,全局访问同一个实例。

用途

用于控制共享资源的访问,维护同一个对象要比维护多个对象更加安全、便捷。

例如:当我们需要一个对象来对打印机(只有一个实体)进行调用,
我们需要调用该对象的方法以实现对打印机资源的使用,因此我们需要这个对象是全局唯一的(因为只有一个打印机实体),以便对打印机创建队列按秩序分配任务。

缺点

缺点主要为全局变量本身的局限性。
基于全局的单例有可能会在某处被修改,从而导致其他位置使用时发生变化。

例如:改变打印机打印模式(单双面),在打印其他文档的时候,单双面的参数已经被上一个任务修改了

示例:

1. 经典的简易单例模式

使用类Singleton创建一个实例,当已经存在一个实例后,则返回已存在的对象,而不是去创建新的对象。

>>> class Singleton(object):
        def __new__(cls):
            # 判断当前类cls是否含有实例instance?
            if not hasattr(cls,'instance'):
                cls.instance = super(Singleton,cls).__new__(cls)
                print("不存在实例,创建新的实例!")
            else:
                print("已存在实例,返回当前实例!")
            return cls.instance
>>> a = Singleton()
不存在实例,创建新的实例!

>>> b = Singleton()
已存在实例,返回当前实例!

2. Lazy实例化单例模式

相比简易单例模式,Lazy实例化可以做到只有在需要用到实例的时候,才对实例进行实例化,可以节约资源。
例如:
使用类Singleton创建一个实例,当已经存在一个实例后,则返回已存在的对象,而不是去创建新的对象。

>>> class Singleton(object):
        instance = None
        def __init__(self):
            if not Singleton.instance:
                print("执行了init初始化,但是并没有实例!")
            else:
                print("执行了init初始化,实例已经存在!")
                
        @classmethod
        def getInstance(cls):
            if not cls.instance:
                cls.instance = Singleton()
                print("没有实例,实例化新对象!")
            else:
                print("已存在实例,返回已有对象")
            return cls.instance
            
>>> a = Singleton() # 初始化类,但是并没有实例
执行了init初始化,但是并没有实例!

>>> print(a.instance) 
None

>>> Singleton.getInstance() # 调用该方法来真正实例化对象
执行了init初始化,但是并没有实例!
没有实例,实例化新对象!

>>> print(a.instance) 
<__main__.Singleton object at 0x000001EA046A5550>

>>> b = Singleton() # 再次定义时不会创建新实例
执行了init初始化,实例已经存在!

该方法实际上将真正意义上的实例初始化交给了方法getInstance(),当由类定义对象时,其实对象并没有被实例化,只有当调用这个方法的时候,类所属的对象才会被实例化。

3. Monostate(单态)模式

另一个思路为:类可以创建多个实例,但是每一个实例他们的状态和参数都是共享且一致的。在内存中多个实例有着不同的位置,但是所有实例都维护统一的状态。因此,在外界看来依然是单例模式。

变量__dict__在python中是一个特殊的变量,他保存着类所有实例的状态。

>>> class Singleton(object):
        shared_state = {"id":"123"}
        def __init__(self):
            self.name = "s1"
            self.__dict__ = self.shared_state
        
>>> a = Singleton()
>>> print(a)
<__main__.Singleton object at 0x000001EA046B9D30>

>>> print(a.name) # 报错,在初始化的时候 name 属性被 shared_state覆盖了
AttributeError: 'Singleton' object has no attribute 'name'

>>> print(a.__dict__)
{'id': '123'}

>>> b = Singleton()
>>> print(b) # 内存位置不同于a的位置 a: 0x000001EA046B9D30
<__main__.Singleton object at 0x000001EA046B93C8>

>>> b.name = "new name" # 给name属性赋值此时 a 中的name属性也被赋值
>>> print(a.name, b.name)
new name new name

>>> print(a.__dict__, b.__dict__) 
{'id': '123', 'name': 'new name'} {'id': '123', 'name': 'new name'}

4. 使用元类构建单例模式

元类是一个类的类,用来定义类的行为方式,从而自定义自己需要的类。元类的功能十分强大,即可控制类来实现单例模式。即,定义一个只能初始化一个实例的“类”。

>>> class MetaSingleton(type):
    instance = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls.instance:
            cls.instance[cls] = super(MetaSingleton, cls).__call__(*args, **kwargs)
            print("不存在实例,创建新实例")
        else:
            print("实例已经存在,返回已存在实例")
        return cls.instance
        
>>> class Singleton(metaclass = MetaSingleton):
        pass
        
>>> a = Singleton()
不存在实例,创建新实例

>>> b = Singleton()
实例已经存在,返回已存在实例

对于类Singleton来说并没有写任何代码来控制单例模式,是因为其元类MetaSingleton已经限制了他的子类只能存在一个实例。