[Python]Python与设计模式1——单例模式

此系列是对《阿里巴巴技术协会-Python与设计模式系列课程》学习笔记。

一、总线

总线是计算机各种功能不仅或者设备之间传送数据、控制信号等信息的公共通信解决方案之一。现在假设有如下场景:
  某中央处理器(CPU)通过某种协议总心啊与一个信号灯相连,信号灯有64种颜色可以设置,中央处理器上运行着三个线程,都可以对这个信号灯进行控制,并且可以独立设置该信号灯的颜色。抽象掉协议细节(用打印表示),如何实现线程对信号灯的控制逻辑?
  最先想到的无疑是加线程锁进行控制,但是各个线程对锁的控制,加大了模块之间的耦合。下面我们就用设计模式中的单例模式来解决问题。

二、单例模式

单例模式是指:保证仅有一个实例,并提供一个访问它的全局 访问点。具体到此例中,总线对象,就是一个单例,他仅有一个实例,各个线程对总线的访问只有一个全局访问点,即唯一的实例。
  
单例模式的优点:

  • 由于单例模式要求在全局内只有一个实例,因而可以节省较多的内存空间;
  • 全局只有一个接入点,可以很好的进行数据的同步控制,避免多重占用;
  • 单例可长驻内存,减少系统开销

单例模式的缺点:

  • 扩展比较困难
  • 某种情况下会导致“资源瓶颈”
  • 单例模式是并发协作软件模块中需要最先完成的,因为不利于测试
  • 赋予单例太多职责,某种程度上违反单一职责原则

单例模式的应用举例:

  • 生成全局唯一的序列号
  • 访问全局复用的唯一资源,如磁盘、总线等
  • 系统全局统一管理,如Windows下的Task Manager
  • 网站计数器

三、代码如下:

#encoding = utf8
import threading
import time

#使用__new__方法来实现单例模式
class Singleton(object):  #抽象单例
    def __new__(cls, *args, **kw):
    	#把类实例绑定到类变量_instance上,如果cls._instance为None,
    	#表示该类还没有被实例化过,实例化该类并返回
    	#如果cls._instance不为None,表示该类已实例化直接返回cls._instance
        if not hasattr(cls,'_instance'): 
            orig = super(Singleton, cls) #super()调用父类,创建实例属性
            cls._instance =orig.__new__(cls,*args,**kw)
        return cls._instance

#总线
class Bus(Singleton):
    lock = threading.RLock() #加载线程的锁对象(多重锁,在同一线程中可被多次acquire)
    def sendData(self,data):
        self.lock.acquire()  #获取总线控制权
        time.sleep(3)
        print('Sending Single Date...',data) 
        self.lock.release()  #释放线程锁
#线程对象,为更加说明单例的含义,这里将bus对象实例化写在run里
class VisitEntity(threading.Thread):
    my_bus = ""
    name = ""
    def getName(self):
        return self.name
    def setName(self, name: str):
        self.name = name
    def run(self):
        self.my_bus = Bus()
        self.my_bus.sendData(self.name)

if __name__ == '__main__':
    for i in range(3):
        print("Entity %d begin to run..."%i)
        my_entity = VisitEntity()
        my_entity.setName("Entity_"+str(i))
        my_entity.start() #start()方法用来启动多线程

在这里插入图片描述
在程序的运行中,三个线程同时运行(运行结果的前三行很快被打印出来),然后分别占用总线资源(后三行每隔3秒打印一行)。虽然看上去总线Bus被实例化了三次,但实际上在内存里只有一个实例。(因为__new__()方法会进行判断,实例化一次后_instance属性就会存在,不会进入if模块执行)

四、知识点

1、静态方法、普通方法、类方法

- 静态方法:

①静态方法是类中的函数,不需要实例(不需要self参数)

②主要用来存放逻辑性的代码,与类本身没有交互,即静态方法中不会涉及到类内的方法和属性,若想调用类内的方法和属性则可通过 __class__.类属性。

③形式:添加@staticmethod装饰器

④调用:直接类名调用或者实例化调用

注意:在Python 2 中,如果一个类的方法不需要self参数,必须声明为静态方法,即加上@staticmethod装饰器,从而不带实例调用它。python3中,如果一个类的方法不需要self参数,不再需要声明为静态方法,但是这样的话只能通过类去调用这个方法,如果使用实例去调用方法会引发异常,因为会自动传入一个self参数
- 类方法:

①类方法传入的第一个参数是cls,是类本身。

②类方法可以通过类直接调用,过通过实例直接调用

③形式:添加@classmethod装饰器

- 实例方法

①除了静态方法和类方法外,类的其他方法都属于实例方法

②实例方法需要将类实例化后调用,如果使用类直接带哦用实例方法,需要显式的将实例作为参数传入

2、new()方法

Python中存在于类里面的构造方法__init__()负责将类实例化,而在__init__()启动之前,__new__()决定是否要使用该__init__()方法,因为__new__()可以调用其他类的构造方法或者返货别的对象来作为本类的实例。(如以上代码中 return cls._instance)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值