单列模式,装饰器、new方法、类/静态方法实现单列模式

一、单列模式
单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。

如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 Config 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 Config 对象的实例,这就导致系统中存在多个 Config 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 Config 这样的类,我们希望在程序运行期间只存在一个实例对象。

二、装饰器实现单列模式

通过python的闭包原理,装饰器能记得外层命名空间装饰器原理参考本文

def single_decorator(cls):
    single = {}
    def wrapper(*args, **kwargs):
        if not single.get(cls.__name__):
            single[cls.__name__] = cls(*args, **kwargs)
        return single[cls.__name__]
    return wrapper

@single_decorator
class School:
    def __init__(self, name, addr, capital, represent):
        self.__name = name      #学校名
        self.__addr = addr      #地址
        self.__registered_capital = capital     #注册资金
        self.__represent = represent        #法人代表


    def get_info(self):
        return "校名: {} 地址: {} 法人代表: {}".format(self.__name, self.__addr, self.__represent)

    @staticmethod
    def show():
        print(School._isxx)

ss= School('古天乐学校', '大凉山', '100.000', '古天乐')
ss2= School('施明德', '台湾?', '1.000.000', '瞎写的')
print('实例一id: %s'%(id(ss)))
print('实例二id: %s'%(id(ss2)))
print(ss.get_info())
print(ss2.get_info())


#运行结果为:
实例一id: 397109139440
实例二id: 397109139440
校名: 古天乐学校 地址: 大凉山 法人代表: 古天乐
校名: 古天乐学校 地址: 大凉山 法人代表: 古天乐

这样就可以将这个装饰器装饰到任何一个类上,完成单列了

 

三、__new__方法+静态字段实现单列模式
 
class Single:
    _single = None
    def __init__(self, value):
        self.v = value
        print(self.v)

    def __new__(cls, *args, **kwargs):
        if Single._single:
            return Single._single
        else:
            Single._single = super(Single, cls).__new__(cls)
            print("只执行一次")
            return Single._single

s2 = Single(2)
s3 = Single(3)
s4 = Single(4)

print(id(s2))
print(id(s3))
print(id(s4))

#输出结果为
只执行一次
2
3
4
s2的id为: 278042421064
s3的id为: 278042421064
s4的id为: 278042421064
  • 和类方法相类似,可以看见,s2/s3/s4 都是同一个id 是同一个实例,尽管实例时传入的值不一样
四、静态方法+静态字段实现单列模式
平时我们在链接数据库时,一个程序,也是只需要一个链接就够了,我们不希望一个程序产生很多实例去连接到数据库,这样每个链接都操作数据库,不但浪费了内存空间,还可能导致数据修改混乱
class Sqlpool:
    __single = None #创建一个静态字段
    def __init__(self):
        #封装数据库链接需要的信息
        self.ip = "192.168.1.1"
        self.port = 3306
        self.pwd = "1234567"
        self.username = "xxxxxx"
        
        #链接数据库
        self.connect = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] #假如创建了9个链接数据库的线

    @staticmethod 
    def produce():
        if Sqlpool.__single: #判断静态字段是否有值
            return Sqlpool.__single #如果有值返回静态字段的值
        else:
            Sqlpool.__single = Sqlpool() #没有就实例一个对象给他
            return Sqlpool.__single     #将实例返回

#这样,无论创建多少个访问,对象时,都是一个对象,这样不会占用内存
conn1 = Sqlpool.produce() #创建一个访问对象
conn2 = Sqlpool.produce() #创建二个访问对象

原理都差不多。这个没有装饰器好用

五、类/类方法直接实现
class Singleton(object):

    def __init__(self):
        pass

    @classmethod
    def get(cls, *args, **kwargs):
        if not hasattr(Singleton, "_single"):
            Singleton._single = Singleton(*args, **kwargs)
        return Singleton._single

类方法这儿实现单列模式还有优化,就不多说了,是多线程问题。
这儿本身原理和静态方法差不多。

posted @ 2018-08-20 12:00  G1733  阅读(302)  评论(0编辑  收藏  举报