單例模式(Singleton Pattern)是一種常用的軟件設(shè)計(jì)模式琉兜,該模式的主要目的是確保某一個(gè)類只有一個(gè)實(shí)例存在齿兔。當(dāng)你希望在整個(gè)系統(tǒng)中丙曙,某個(gè)類只能出現(xiàn)一個(gè)實(shí)例時(shí)拯杠,單例對(duì)象就能派上用場(chǎng)善涨。
比如窒盐,某個(gè)服務(wù)器程序的配置信息存放在一個(gè)文件中,客戶端通過(guò)一個(gè) AppConfig 的類來(lái)讀取配置文件的信息钢拧。如果在程序運(yùn)行期間蟹漓,有很多地方都需要使用配置文件的內(nèi)容,也就是說(shuō)源内,很多地方都需要?jiǎng)?chuàng)建 AppConfig 對(duì)象的實(shí)例葡粒,這就導(dǎo)致系統(tǒng)中存在多個(gè) AppConfig 的實(shí)例對(duì)象,而這樣會(huì)嚴(yán)重浪費(fèi)內(nèi)存資源姿锭,尤其是在配置文件內(nèi)容很多的情況下塔鳍。事實(shí)上,類似 AppConfig 這樣的類呻此,我們希望在程序運(yùn)行期間只存在一個(gè)實(shí)例對(duì)象轮纫。
在 Python 中,我們實(shí)現(xiàn)單例模式可以用如下方式:
"""
1.類由type創(chuàng)建焚鲜,創(chuàng)建類時(shí)掌唾,type的__init__方法自動(dòng)執(zhí)行,類() 執(zhí)行type的 __call__方法(類的__new__方法,類的__init__方法)
2.對(duì)象由類創(chuàng)建忿磅,創(chuàng)建對(duì)象時(shí)糯彬,類的__init__方法自動(dòng)執(zhí)行,對(duì)象()執(zhí)行類的 __call__ 方法
"""
class Singleton(type):
"""Singleton Metaclass"""
def __init__(self, name, bases, dic):
super(Singleton, self).__init__(name, bases, dic)
self.instance = None
def __call__(self, *args, **kwargs):
print(self.instance)
if self.instance is None:
self.instance = super(Singleton, self).__call__(*args, **kwargs)
return self.instance
class test(metaclass=Singleton): # 指定創(chuàng)建Foo的type為SingletonType
def __init__(self):
self.json_config = None
print(test().json_config)
test().json_config = {"a":1}
print(test().json_config)
print(test())
print(test())
"""
輸出結(jié)果
None
{'a': 1}
<__main__.test object at 0x000001B114A76FD0>
<__main__.test object at 0x000001B114A76FD0>
由此可以看出來(lái)葱她,雖然test實(shí)例化了4次
但是每一次都是同一個(gè)實(shí)例撩扒。
"""
'''
實(shí)現(xiàn)帶線程安全鎖的單例
'''
import threading
class SingletonType(type):
_instance_lock = threading.Lock()
def __call__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
with SingletonType._instance_lock:
if not hasattr(cls, "_instance"):
cls._instance = super(SingletonType,cls).__call__(*args, **kwargs)
return cls._instance
class Foo(metaclass=SingletonType):
def __init__(self,name):
self.name = name
obj1 = Foo('name')
obj2 = Foo('name')
print(obj1,obj2)
'''
可以看到在兩者區(qū)別是在call魔術(shù)方法內(nèi)
后者增加了線程鎖
'''