Python设计模式-单例模式
基于Python3.5.2,代码如下
import threading
import time
class Singleton (object) :
def __new__ (cls, *args, **kwargs) :
if not hasattr(cls,'_instance' ):
print("first" )
orig = super(Singleton,cls)
cls._instance = orig.__new__(cls,*args,**kwargs)
return cls._instance
def __init__ (self) :
print("init" )
class Bus (Singleton) :
lock = threading.RLock()
def sendData (self,data) :
self.lock.acquire()
time.sleep(3 )
print("sending Signal Data ," ,data)
self.lock.release()
class VisitEntity (threading.Thread) :
my_bus = ""
name = ""
def getName (self) :
return self.name
def setName (self,name) :
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()
单例模式分析与解读
单例模式:
单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
单例模式的应用场景:
1、生成全局惟一的序列号;
2、访问全局复用的惟一资源,如磁盘、总线等;
3、单个对象占用的资源过多,如数据库等;
4、系统全局统一管理,如Windows下的Task Manager;
5、网站计数器。
6、单个数据库连接对象。
解读:
在单例模式中,在类实现单例过程中,在多线程的情景下,有可能会创建多个实例,所以在单例的创建过程中,需要对生成单例的过程加锁,防止出现多次创建。
1、在Singleton类中,由于Python创建对象是通过__new__()方法创建,给Singleton添加_instance属性来保存创建的实例对象,在__new__()的过程中,如果有_instance则直接返回该实例对象,如果没有则先创建该实例对象然后在返回该对象。
2、在Bus类中,由于Bus继承自Singleton类,该Bus类可以继承Singleton的单例特性。在多线程模型中,Bus类中的sendData方法是需要依次发送消息,所以在sendData中加入线程锁,哪个线程先获得锁就先执行。
3、在VisitEntity类中,利用Python的多线程,进行并发执行。
程序运行结果如下:
Entity 0 begin to run...
first
Entity 1 begin to run...
init
init
Entity 2 begin to run...
init
sending Signal Data , Entity_0
sending Signal Data , Entity_1
sending Signal Data , Entity_2
Bus对象只生成了一次,当其他线程执行Bus()时,都只执行了__init__()方法,没有执行__new__()新建类的方法。
单例模式的优缺点:
优点:
1、由于单例模式要求在全局内只有一个实例,因而可以节省比较多的内存空间;
2、全局只有一个接入点,可以更好地进行数据同步控制,避免多重占用;
3、单例可长驻内存,减少系统开销。
缺点:
1、单例模式的扩展是比较困难的;
2、赋于了单例以太多的职责,某种程度上违反单一职责原则;
3、单例模式是并发协作软件模块中需要最先完成的,因而其不利于测试;
4、单例模式在某种情况下会导致“资源瓶颈”。
备注:
在java中,还存在着饱汉模式和饿汉模式:
饱汉模式:
在第一次被引用时,才将自己实例化。避免开始时占用系统资源,但是有多线程访问安全性问题。
饿汉模式:
在类被加载时就将自己实例化(静态初始化)。其优点是躲避了多线程访问的安全性问题,缺点是提前占用系统资源。