单例模式

意图:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
 
适用性:
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
实现方法:
  • 使用函数装饰器实现单例
  • 使用类装饰器实现单例
  • 使用 __new__ 关键字实现单例
  • 使用 metaclass 实现单例
1.使用 __new__ 关键字实现单例
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
 
示例代码:
#-*- coding:utf-8 -*-
'''
Singleton
'''
# 并在将一个类的实例绑定到类变量_instance上,
# 如果cls._instance为None说明该类还没有实例化过,实例化该类,并返回
# 如果cls._instance不为None,直接返回cls._instance
class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)  # farther class
            cls._instance = orig.__new__(cls)
            # orig =让cls继承指定的父类 Singleton
            # cls._instance = 创建了MyClass('Burgess') 该实例
            # 这两句相当于外面的 a= MyClass('Burgess')
        return cls._instance  # 具体的实例
 
class MyClass(Singleton):
    def __init__(self, name):
        self.name = name
 
 
class Nana(Singleton):
    def __init__(self, name):
        self.name = name
 
a = MyClass("Burgess")
print(a.name)
b = MyClass("Crystal")
print(a.name)
print(b.name)
b.name = 'xx'
print(a.name)
print(b.name)
执行结果:
通过执行结果我们可以看出:一个类永远只允许一个实例化对象,不管多少个进行实例化,都返回第一个实例化的对象
 
2.使用函数装饰器实现单例
以下是实现代码: 
def singleton(cls):
    _instance = {}

    def inner():
        if cls not in _instance:
            _instance[cls] = cls()
        return _instance[cls]
    return inner
    
@singleton
class Cls(object):
    def __init__(self):
        pass

cls1 = Cls()
cls2 = Cls()
print(id(cls1) == id(cls2))
 
3.使用类装饰器实现单例
代码:
class Singleton(object):
    def __init__(self, cls):
        self._cls = cls
        self._instance = {}
    def __call__(self):
        if self._cls not in self._instance:
            self._instance[self._cls] = self._cls()
        return self._instance[self._cls]

@Singleton
class Cls2(object):
    def __init__(self):
        pass

cls1 = Cls2()
cls2 = Cls2()
print(id(cls1) == id(cls2))
同时,由于是面对对象的,这里还可以这么用
class Cls3():
    pass

Cls3 = Singleton(Cls3)
cls3 = Cls3()
cls4 = Cls3()
print(id(cls3) == id(cls4))
 
4.使用 metaclass 实现单例模式
同样,我们在类的创建时进行干预,从而达到实现单例的目的。
在实现单例之前,需要了解使用 type 创造类的方法,代码如下: 
def func(self):
    print("do sth")

Klass = type("Klass", (), {"func": func})

c = Klass()
c.func()
以上,我们使用 type 创造了一个类出来。这里的知识是 mataclass 实现单例的基础。

class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]

class Cls4(metaclass=Singleton):
    pass

cls1 = Cls4()
cls2 = Cls4()
print(id(cls1) == id(cls2))
这里,我们将 metaclass 指向 Singleton 类,让 Singleton 中的 type 来创造新的 Cls4 实例。

 

posted @ 2020-12-12 10:58  盲仔不瞎忙  阅读(36)  评论(0编辑  收藏  举报