【设计模式】单例模式

简介

单例模式,顾名思义,就是在整个程序中,只生成一个实例,即便是重新显示调用,生成的也是相同的实例!主要用在只需要一个对象的业务场景,且不希望每次都重新创建!简单讲就是一次创建,随处使用。

代码实现

python的单例非常简单,有多种实现方式;

通过get_instance

class SingletonPeople:
    """
    通过get_instance实现单例
    """
    def __init__(self):
        self.count = 0

    @staticmethod
    def get_instance():
        if not hasattr(SingletonPeople, "_instance"):
            SingletonPeople._instance = SingletonPeople()
        return SingletonPeople._instance

    def test_instance_method(self, content):
        self.count += 1
        print(content)

成员函数get_instance必须是静态方法,通过类调用来创建实例和获取已生成的实例!

if __name__ == '__main__':
    people = SingletonPeople.get_instance()
    print(id(people))
    people.test_instance_method("this is a singleton class implemented by static method get_instance")
    print(people.count)
    spare = SingletonPeople.get_instance()
    print(id(spare))
    spare.test_instance_method("this is a spare people")
    print(spare.count)
4323587696
this is a singleton class implemented by static method get_instance
1
4323587696
this is a spare people
2

Process finished with exit code 0

通过魔术方法__new__

class SingletonDog:
    """
    通过__new__来实现单例
    """
    def __init__(self):
        if not hasattr(self, "num"):
            self.num = 0

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

    def test_instance_method(self, content):
        self.num += 1
        print(content)

get_instance方法简单高效,不过由于python的语言特性,一切皆可访问,如果显式实例化的依然无法避免创建多个实例的情况。那么可以在类新建的时候,保证只生成单个实例。

python中类的创建在魔术方法__new__中,通过__new__创建实例之后,再调用__init__方法执行参数初始化操作。

所以上面的代码,能够保证每次实例化都是同一个类实例。

if __name__ == '__main__':
    dog = SingletonDog()
    print(id(dog))
    dog.test_instance_method("this is a singleton class implemented by static method get_instance")
    print(dog.num)
    spare = SingletonDog()
    print(id(spare))
    spare.test_instance_method("this is a spare people")
    print(spare.num)
4438931296
this is a singleton class implemented by static method get_instance
1
4438931296
this is a spare people
2

Process finished with exit code 0

有一点需要注意的是,上面的__new__方法中实现的,并不是线程安全的;若需要保证线程安全,比如实现日志单例类,需要加上线程锁

class SingletonDog:
    """
    通过__new__来实现单例
    """
    lock = Lock()

    def __init__(self):
        if not hasattr(self, "num"):
            self.num = 0

    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, "_instance"):
            with cls.lock:
                if not hasattr(cls, "_instance"):
                        cls._instance = super().__new__(cls, *args, **kwargs)
        return cls._instance

    def test_instance_method(self, content):
        self.num += 1
        print(content)

多线程中如果遇到实例创建比较耗时的单例,就会造成创建多次实例的情况!这种就丧失了单例功能。
所以在__new__执行了加锁操作。锁定当前的资源,之所以加了两层hasattr(cls, “_instance”)的判断,是为了防止,多个线程同时执行到with cls.lock语句,导致创建多次实例!

通过__new__方法创建的单例,每次获取实例对象都会调用一次__init__方法,重新初始化一遍实例参数。在类的内部,实例参数相当于全局变量;所以单例的初始化参数需要注意!当然也可以利用这一特性,实现一些功能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值