Python实现设计模式--01.单例模式(Singleton Pattern)

1、基于模块引用(饱汉模式)

建立文件Emperor_Singleton.py,内容如下:

# 皇帝类
class Emperor(object):
    def say(self):
        print('我是唯一的皇帝!')


emperor = Emperor()

测试内容如下:

from singleton.Emperor_Singleton import emperor

emperor.say()

运行测试类,打印结果:

我是唯一的皇帝!

2、基于__new__方法,继承父单例类(饿汉模式,  __new__方法类似其他语言的构造函数)

建立文件Singleton.py,内容如下(父单例类):

class Singleton:
    __instance = None

    def __new__(cls, *args, **kwargs):
        if Singleton.__instance is None:
            Singleton.__instance = object.__new__(cls, *args)
        return Singleton.__instance

测试内容如下:

import random

from singleton.Singleton import Singleton


class Emperor(Singleton):
    def __init__(self):
        if not hasattr(self, 'name'):
            self.name = random.choice(['秦始皇', '汉武帝', '康熙', '汉献帝'])

    def say(self):
        print('我是皇帝:', self.name, ',我的id:', id(self))


for i in range(10):
    Emperor().say()
运行测试类,打印结果:
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576
我是皇帝: 汉献帝 , 我的id: 4330069576

3、基于__new__方法的线程安全性

上面第2点基于__new__方法,存在线程安全问题。我们实验下,将Singleton类创建对象的时间延长,如下:

class Singleton:
    __instance = None

    def __new__(cls, *args, **kwargs):
        if Singleton.__instance is None:
            for i in range(5000000):
                continue
            Singleton.__instance = object.__new__(cls, *args)
        return Singleton.__instance

测试文件创建10个线程,如下:

import random
import threading

from singleton.Singleton import Singleton


class Emperor(Singleton):
    def __init__(self):
        if not hasattr(self, 'name'):
            self.name = random.choice(['秦始皇', '汉武帝', '康熙', '汉献帝'])

    def say(self):
        print('我是皇帝:', self.name, ', 我的id:', id(self))


class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        Emperor().say()


if __name__ == '__main__':
    threads = []
    for i in range(10):
        threads.append(MyThread())

    for t in threads:
        t.start()

    for t in threads:
        t.join()
运行测试类,打印结果:
我是皇帝: 汉武帝 , 我的id: 4330917960
我是皇帝: 康熙 , 我的id: 4330918016
我是皇帝: 秦始皇 , 我的id: 4330917960
我是皇帝: 秦始皇 , 我的id: 4330918016
我是皇帝: 秦始皇 , 我的id: 4330917960
我是皇帝: 汉献帝 , 我的id: 4330918016
我是皇帝: 秦始皇 , 我的id: 4330917960
我是皇帝: 秦始皇 , 我的id: 4330918016
我是皇帝: 秦始皇 , 我的id: 4330917960
我是皇帝: 秦始皇 , 我的id: 4330918016

可以看出,这里显然是线程不安全的……

4、编写线程安全的饿汉单例,基于__new__方法

修改Singleton类,加入双重锁机制:

import threading


class Singleton:
    __instance = None
    __lock = threading.Lock()

    def __new__(cls, *args, **kwargs):
        if Singleton.__instance is None:
            Singleton.__lock.acquire()
            if Singleton.__instance is None:
                for i in range(5000000):
                    continue
                Singleton.__instance = object.__new__(cls, *args)
            Singleton.__lock.release()
        return Singleton.__instance

还是用上面的测试文件,结果如下:

我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552
我是皇帝: 康熙 , 我的id: 4330938552

至此,一个标准的基于__new__方法的单例模式就完成啦!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值