上次我們簡(jiǎn)單了解了一下什么是單例模式,今天我們繼續(xù)探究。
上次的內(nèi)容點(diǎn)這
上次們討論的是GoF的單例設(shè)計(jì)模式,該模式是指:一個(gè)類有且只有一個(gè)對(duì)象。通常我們需要的是讓實(shí)例共享一個(gè)相同的裝態(tài) 比如數(shù)據(jù)庫(kù)連接。Alex
Martelli的建議的是開(kāi)發(fā)人員應(yīng)該關(guān)注狀態(tài)和行為,而不是同一性,因此它也被稱為Monostate(單態(tài))模式。
Monostate單例模式的概念
先說(shuō)說(shuō) MonoState 這個(gè)單詞的意思,設(shè)計(jì)模式的名字都是很有意思的,因?yàn)闉榱朔奖憬涣鳌⒂洃?,所以設(shè)計(jì)模式的命名都對(duì) 該模式的意圖進(jìn)行了表述。 Mono
是一個(gè)詞根,英語(yǔ)中 Mono,Mon 都表示的是 1 的意思, state 意思為 " 狀態(tài) " 。 MonoState 的意思就是 " 單一的狀態(tài)
",MonoState 并不限制創(chuàng)建對(duì)象的個(gè)數(shù),但是它的狀態(tài)卻只有一個(gè)狀態(tài)
Monostate單例模式的使用
我們知道在python中,__dict__是用來(lái)存儲(chǔ)對(duì)象屬性的一個(gè)字典,其鍵為屬性名,值為屬性的值。所以下面我們可以使用dict
來(lái)存儲(chǔ)一個(gè)類所有對(duì)象的狀態(tài)。來(lái)看下面這個(gè)例子:
class?useDict:
????__state={"name":"cxa"}
????def?__init__(self):
????????self.age=27
????????self.__dict__=self.__state
m=useDict()
m1=useDict()
m.age=23
print(m)
print(m1)
print(m.__dict__)
print(m1.__dict__)
運(yùn)行以后輸出結(jié)果。
<__builtin__.useDict?instance?at?0x7f78ceacc098>
<__builtin__.useDict?instance?at?0x7f78ceacc128>
{'age':?23,?'name':?'cxa'}
{'age':?23,?'name':?'cxa'}
首先我們看結(jié)果 我們發(fā)現(xiàn)每次對(duì)useDict實(shí)例化都會(huì)創(chuàng)建一個(gè)新的對(duì)象,然后我們通過(guò)m修改了age屬性的值后,m1的age屬性值也發(fā)生了變化。
除此之外我們還可以使用__new__方法本身來(lái)實(shí)現(xiàn)。
class?useNew(object):
????_state={}
????def?__new__(cls,*args,**kwargs):
????????obj=super(useNew,cls).__new__(cls,*args,**kwargs)
????????obj.__dict__=cls._state
????????return?obj
a=useNew()
a1=useNew()
a.x=3
print(a)
print(a1)
print(a.__dict__)
print(a1.__dict__)
下面是輸出結(jié)果
<useNew?object?at?0x7f78ceb873d0>
<useNew?object?at?0x7f78ceb87b50>
{'x':?3}
{'x':?3}
兩種寫(xiě)法的效果是一樣的。
元類的實(shí)現(xiàn)方式
元類是一個(gè)類的類,這就意味著該類是它的元類的實(shí)例。對(duì)于已經(jīng)存在的類來(lái)說(shuō),當(dāng)需要?jiǎng)?chuàng)建對(duì)象的時(shí)候,將調(diào)用python的特殊方法__call__,我們可以通過(guò)使用元類的__call__方法,來(lái)控制一個(gè)對(duì)象的實(shí)例化,具體看下面的例子
一個(gè)數(shù)據(jù)庫(kù)連接的例子
import?pymysql
class?MetaSingleton(type):
????_inst={}
????def?__call__(cls,*args,**kwargs):
????????if?cls?not?in?cls._inst:
????????????cls._inst[cls]=super(MetaSingleton,cls).__call__(*args,**kwargs)
????????return?cls._inst[cls]
class?MysqlDb(metaclass=MetaSingleton):
?????connection=None
?????def?conn(self):
????????if?self.connection?is?None:
?????????????self.connection=?pymysql.connect(host='127.0.0.1',?port=3306
,?user='root',
?????????????passwd='Aa1234',?db='user',?charset='utf8mb4')
?????????????self.cursor=self.connection.cursor()
????????return??self.cursor
d1=MysqlDb().conn()
d2=MysqlDb().conn()
單例模式的缺點(diǎn)
介紹了這么長(zhǎng)時(shí)間的單例模式,也許你會(huì)有疑問(wèn),那單例模式有什么缺點(diǎn)呢?
雖然單例模式的效果很好但是依然存在一些問(wèn)題,因?yàn)閱卫哂腥衷L問(wèn)權(quán)限,所以可能出現(xiàn)以下問(wèn)題:
* 全局變量可能在某個(gè)地方被改了但是不知道。(比如之前的那個(gè)使用__dict__的例子)。
* 可能會(huì)對(duì)同一個(gè)對(duì)象創(chuàng)建多個(gè)引用。由于單例只創(chuàng)建一個(gè)對(duì)象,因此這種情況下會(huì)對(duì)一個(gè)對(duì)象創(chuàng)建對(duì)個(gè)引用。
* 所有依賴于全局變量的類都會(huì)由于一個(gè)類的改變而緊密耦合為全局?jǐn)?shù)據(jù),從而可能在無(wú)意中影響另一個(gè)類。
到此為止,我們就把單例模式的相關(guān)內(nèi)容介紹完了,后續(xù)也許會(huì)寫(xiě)關(guān)于其他設(shè)計(jì)模式的相關(guān)文章,如果你喜歡的話,轉(zhuǎn)發(fā)到朋友圈和小伙兒們一起分享吧。
熱門(mén)工具 換一換
