摘要:實(shí)現(xiàn)實(shí)現(xiàn)單例模式有多種方案使用提供了非常易用的類,只要繼承它,就會(huì)成為單例。參考鏈接單例模式最后,感謝女朋友支持。
問(wèn)題:現(xiàn)代化的巧克力工廠具備計(jì)算機(jī)控制的巧克力鍋爐。鍋爐做的事情就是把巧克力和牛奶融在一起,然后送到下一個(gè)階段,以制成巧克力棒。下邊是一個(gè)巧克力公司鍋爐控制器的代碼,仔細(xì)觀察一下,這段代碼有什么問(wèn)題?
class ChocolateBoiler(object): def __init__(self): self.empty = True self.boiled = False def fill(self): # 向鍋爐填充巧克力和牛奶混合物 # 在鍋爐內(nèi)填充原料時(shí),鍋爐必須是空的。 # 一旦填入原料,就要把empty 和 boiled 標(biāo)志設(shè)置好 if self.empty: self.empty = False self.boiled = False def drain(self): # 排出煮沸的巧克力和牛奶 # 鍋爐排出時(shí),必須是滿的且煮沸的。 # 排出完畢empty 設(shè)置為 true if not self.empty and self.boiled: self.empty = True def boil(self): # 將顱內(nèi)物煮沸 # 煮混合物時(shí),鍋爐內(nèi)必須是滿的且沒(méi)有煮沸過(guò) # 一旦煮沸,就把 boiled 設(shè)置為 true if not self.empty and not self.boiled: self.boiled = True
從代碼可以看出,他們加入了多種判斷,以防止不好的事情發(fā)生。如果同時(shí)存在兩個(gè)ChocolateBoiler實(shí)例,那這么多判斷豈不是失去作用了。那我們改如何實(shí)現(xiàn)這個(gè)需求呢?這個(gè)問(wèn)題的核心是,我們要先判斷實(shí)例是不是已經(jīng)存在,如果存在就不再創(chuàng)建。
_chocolate_boiler_instance = None # 聲明實(shí)例 def chocolate_boiler(): global _chocolate_boiler_instance # 使用全局變量 if _chocolate_boiler_instance is not None: # 判斷是否存在,如果存在,直接返回 return _chocolate_boiler_instance else: # 如果不存在,創(chuàng)建一個(gè)新的 _chocolate_boiler_instance = ChocolateBoiler() return _chocolate_boiler_instance
現(xiàn)在我們需要獲取 ChocolateBoiler 實(shí)例的時(shí)候只需要調(diào)用 chocolate_boiler 方法獲取實(shí)例即可保證同時(shí)只有一個(gè) ChocolateBoiler實(shí)例。
這種保證 ChocolateBoiler類只有一個(gè)實(shí)例,并提供一個(gè)全局訪問(wèn)點(diǎn)的模式,就是單例模式。
單例模式 定義單例模式:確保一個(gè)類只有一個(gè)實(shí)例,并提供一個(gè)全局訪問(wèn)點(diǎn)。
也就是說(shuō),我們使用單例模式要把某個(gè)類設(shè)計(jì)成自己管理的一個(gè)多帶帶實(shí)例,同時(shí)也避免其他類再自行產(chǎn)生實(shí)例。并且只允許通過(guò)單例類獲取單例的實(shí)例。
我們也提供對(duì)這個(gè)實(shí)例的全局訪問(wèn)點(diǎn):當(dāng)你需要實(shí)例時(shí),像類查詢,它會(huì)返回單個(gè)實(shí)例。
實(shí)現(xiàn)python 實(shí)現(xiàn)單例模式有多種方案:
使用 metaclass《python cookbook》提供了非常易用的 Singleton 類,只要繼承它,就會(huì)成為單例。
# python 3 代碼實(shí)現(xiàn) class Singleton(type): def __init__(self, *args, **kwargs): self.__instance = None super().__init__(*args, **kwargs) def __call__(self, *args, **kwargs): if self.__instance is None: # 如果 __instance 不存在,創(chuàng)建新的實(shí)例 self.__instance = super().__call__(*args, **kwargs) return self.__instance else: # 如果存在,直接返回 return self.__instance class Spam(metaclass=Singleton): def __init__(self): print("Creating Spam") a = Spam() b = Spam() print(a is b) # 這里輸出為 True
元類(metaclass)可以控制類的創(chuàng)建過(guò)程,它主要做三件事:
攔截類的創(chuàng)建
修改類的定義
返回修改后的類
例子中我們構(gòu)造了一個(gè)Singleton元類,并使用__call__方法使其能夠模擬函數(shù)的行為。構(gòu)造類 Spam 時(shí),將其元類設(shè)為Singleton,那么創(chuàng)建類對(duì)象 Spam 時(shí),行為發(fā)生如下:
Spam = Singleton(name,bases,class_dict),Spam 其實(shí)為Singleton類的一個(gè)實(shí)例。
創(chuàng)建 Spam 的實(shí)例時(shí),Spam()=Singleton(name,bases,class_dict)()=Singleton(name,bases,class_dict).__call__(),這樣就將 Spam 的所有實(shí)例都指向了 Spam 的屬性 __instance上。
使用 new我們可以使用 new 來(lái)控制實(shí)例的創(chuàng)建過(guò)程,代碼如下:
class Singleton(object): __instance = None def __new__(cls, *args, **kw): if not cls.__instance: cls.__instance = super().__new__(cls, *args, **kw) return cls.__instance class Foo(Singleton): a = 1 one = Foo() two = Foo() assert one == two assert one is two assert id(one) == id(two)
通過(guò) new 方法,將類的實(shí)例在創(chuàng)建的時(shí)候綁定到類屬性 __instance 上。如果cls.__instance 為None,說(shuō)明類還未實(shí)例化,實(shí)例化并將實(shí)例綁定到cls.__instance 以后每次實(shí)例化的時(shí)候都返回第一次實(shí)例化創(chuàng)建的實(shí)例。注意從Singleton派生子類的時(shí)候,不要重載__new__。
使用裝飾器import functools def singleton(cls): """ Use class as singleton. """ # 首先將 __new__ 方法賦值給 __new_original__ cls.__new_original__ = cls.__new__ @functools.wraps(cls.__new__) def singleton_new(cls, *args, **kw): # 嘗試從 __dict__ 取 __it__ it = cls.__dict__.get("__it__") if it is not None: # 如果有值,說(shuō)明實(shí)例已經(jīng)創(chuàng)建,返回實(shí)例 return it # 如果實(shí)例不存在,使用 __new_original__ 創(chuàng)建實(shí)例,并將實(shí)例賦值給 __it__ cls.__it__ = it = cls.__new_original__(cls, *args, **kw) it.__init_original__(*args, **kw) return it # class 將原有__new__ 方法用 singleton_new 替換 cls.__new__ = singleton_new cls.__init_original__ = cls.__init__ cls.__init__ = object.__init__ return cls # # 使用示例 # @singleton class Foo: def __new__(cls): cls.x = 10 return object.__new__(cls) def __init__(self): assert self.x == 10 self.x = 15 assert Foo().x == 15 Foo().x = 20 assert Foo().x == 20
這種方法的內(nèi)部實(shí)現(xiàn)和使用 __new__ 類似:
首先,將 new 方法賦值給 new_original__,原有 new 方法用 singleton_new 替換,定義 init_original 并將 cls.__init 賦值給 init_original
在 singleton_new 方法內(nèi)部,嘗試從 dict 取 __it__(實(shí)例)
如果實(shí)例不存在,使用 new_original 創(chuàng)建實(shí)例,并將實(shí)例賦值給 __it__,然后返回實(shí)例
最簡(jiǎn)單的方式將名字singleton綁定到實(shí)例上,singleton就是它自己類的唯一對(duì)象了。
class singleton(object): pass singleton = singleton()
https://github.com/gusibi/Metis/blob/master/apis/v1/schemas.py#L107 使用的就是這種方式,用來(lái)獲取全局的 request
參考鏈接Python 的模塊就是天然的單例模式,因?yàn)槟K在第一次導(dǎo)入時(shí),會(huì)生成 .pyc 文件,當(dāng)?shù)诙螌?dǎo)入時(shí),就會(huì)直接加載 .pyc 文件,而不會(huì)再次執(zhí)行模塊代碼。因此,我們只需把相關(guān)的函數(shù)和數(shù)據(jù)定義在一個(gè)模塊中,就可以獲得一個(gè)單例對(duì)象了。
Creating a singleton in Python
Python單例模式
Why is __init__() always called after __new__()?
最后,感謝女朋友支持。
歡迎關(guān)注(April_Louisa) | 請(qǐng)我喝芬達(dá) |
---|---|
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/44499.html
摘要:本篇文章總結(jié)了目前主流的實(shí)現(xiàn)單例模式的方法供讀者參考。使用實(shí)現(xiàn)單例模式同樣,我們?cè)陬惖膭?chuàng)建時(shí)進(jìn)行干預(yù),從而達(dá)到實(shí)現(xiàn)單例的目的。 很多初學(xué)者喜歡用 全局變量 ,因?yàn)檫@比函數(shù)的參數(shù)傳來(lái)傳去更容易讓人理解。確實(shí)在很多場(chǎng)景下用全局變量很方便。不過(guò)如果代碼規(guī)模增大,并且有多個(gè)文件的時(shí)候,全局變量就會(huì)變得比較混亂。你可能不知道在哪個(gè)文件中定義了相同類型甚至重名的全局變量,也不知道這個(gè)變量在程序的某...
摘要:前言單例模式是設(shè)計(jì)模式中最簡(jiǎn)單最容易理解的一種,維基百科的定義如下單例模式,也叫單子模式,是一種常用的軟件設(shè)計(jì)模式。 前言 單例模式是設(shè)計(jì)模式(Design Pattern)中最簡(jiǎn)單、最容易理解的一種,維基百科[1]的定義如下: 單例模式,也叫單子模式,是一種常用的軟件設(shè)計(jì)模式。在應(yīng)用這個(gè)模式時(shí),單例對(duì)象的類 類 (計(jì)算機(jī)科學(xué)))必須保證只有一個(gè)實(shí)例存在。許多時(shí)候整個(gè)系統(tǒng)只需要擁有一...
摘要:在中,我們可以用多種方法來(lái)實(shí)現(xiàn)單例模式使用模塊使用使用裝飾器使用元類使用模塊其實(shí),的模塊就是天然的單例模式,因?yàn)槟K在第一次導(dǎo)入時(shí),會(huì)生成文件,當(dāng)?shù)诙螌?dǎo)入時(shí),就會(huì)直接加載文件,而不會(huì)再次執(zhí)行模塊代碼。 單例模式 單例模式(Singleton Pattern)是一種常用的軟件設(shè)計(jì)模式,該模式的主要目的是確保某一個(gè)類只有一個(gè)實(shí)例存在。當(dāng)你希望在整個(gè)系統(tǒng)中,某個(gè)類只能出現(xiàn)一個(gè)實(shí)例時(shí),單例對(duì)...
摘要:使用元類可以控制類的創(chuàng)建過(guò)程,它主要做三件事攔截類的創(chuàng)建修改類的定義返回修改后的類使用元類實(shí)現(xiàn)單例模式的代碼如下執(zhí)行結(jié)果 單例模式 單例模式(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è) ...
摘要:簡(jiǎn)單工廠模式工廠模式有一種非常形象的描述,建立對(duì)象的類就如一個(gè)工廠,而需要被建立的對(duì)象就是一個(gè)個(gè)產(chǎn)品在工廠中加工產(chǎn)品,使用產(chǎn)品的人,不用在乎產(chǎn)品是如何生產(chǎn)出來(lái)的。單例模式的單例模式,所謂單例模式就是一個(gè)類只能創(chuàng)建一個(gè)實(shí)例化。 簡(jiǎn)單工廠模式 工廠模式有一種非常形象的描述,建立對(duì)象的類就如一個(gè)工廠,而需要被建立的對(duì)象就是一個(gè)個(gè)產(chǎn)品;在工廠中加工產(chǎn)品,使用產(chǎn)品的人,不用在乎產(chǎn)品是如何生產(chǎn)出來(lái)...
閱讀 2427·2021-11-25 09:43
閱讀 1203·2021-09-07 10:16
閱讀 2620·2021-08-20 09:38
閱讀 2947·2019-08-30 15:55
閱讀 1465·2019-08-30 13:21
閱讀 896·2019-08-29 15:37
閱讀 1449·2019-08-27 10:56
閱讀 2097·2019-08-26 13:45