创建型模式之单例模式

单例模式确保应用程序中始终只有一个存活的实例。例如你想要资源访问限制的时候,或者数据库连接类等等,再比如服务配置文件放在一个目录中,程序启动需要通过Configure类加载配置文件。如果每个程序都去实例化一个Configure类,尤其conf文件还比较大

这个时候就会造成内存浪费,这种情况单例模式就派上用场了。

单例模式有如下几种实现方式

1.使用带有函数或者变量的模块,如数据库连接的的配置文件

MONGODB = "xxx"
MYSQL = "xxx"
REDIS = "xxx"

将它们保存在settings.py的文件中,然后其他程序直接导入即可,python这种导入本身就是单例模式的实现。

from settings import MONGODB

如果需要单例的类就实例化

class Singleton(object):
    pass

singleton = Singleton()

然后导入实例化之后的方法就可以了

from xxx import singleton

2.使用单例模糊的装饰器

def Singleton(cls):
    cls_instance = {}
    def is_instance(*args, **kargs):
        if cls not in cls_instance:
            cls_instance[cls] = cls(*args, **kargs)
        return cls_instance[cls]
    return is_instance

@Singleton
class SingletonTest(object):

    def __init__(self, v):
        self.value = v

t = SingletonTest(2)
t2 = SingletonTest(3)
print(t.value, t2.value)
print(id(t) == id(t2))

>>> 2, 2
>>> True

3.使用__new__实现

在类实例化的时候,python首先调用__new__方法,然后在执行__init__进行初始化。所以我们可以在__new__做手脚。

class Singleton(object):
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

t1 = Singleton()
t2 = Singleton()
print(id(t1) == id(t2))
>>> True

注意: 这样写非常危险,如果你已经创建了一个基类,然后你尝试对基类的子类进行实例化,这个时候问题就出现了。

结果都会依赖实例创建的顺序,父类先创建就会出问题,子类先创建就是正常的。在大型应用中这是难以预测的错误千万要注意。如果单例不会被子类实例化,这个方法就没有问题。

4.使用元类实现

 

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

class SingletonTest(metaclass=Singleton): # 指定创建Foo的type为SingletonType
    def __init__(self, v):
        self.value = v


obj = SingletonTest('xx')
obj2 = SingletonTest('xxx')
print(id(obj) == id(obj2))
print(obj.value, obj2.value)

通常我们实例化都会生成一个新实例

1 class Singleton(object):
2     pass
3 
4 a = Singleton()
5 b = Singleton()
6 print(id(a) == id(b))
>>> False

 

posted @ 2018-08-18 17:49  leonharetd  阅读(154)  评论(0编辑  收藏  举报