# Python設計模式 單例模式

早睡蟲莽發表於2020-07-05

什麼是單例模式?

單例模式是一種寫程式的方式,用單例模式設計的類,無論你去例項化多少次,得到的都是同一個例項,一般我們設計的類每次例項化都會生成不同的例項,但是單例模式就是反其道而行之,就像下面這樣:

上圖中的ClassA和ClassB 都是採用的 單例設計模式,而ClassC沒有采用單例設計模式

我們可以清晰的看到 ClassA的兩個不同的例項在記憶體中的地址是相同的,也就是說兩次例項化得到的物件是同一個物件,ClassB和ClassA也是一樣的,因為都採用了單例設計模式, 而ClassC因為沒有采用單例設計模式所以他的兩個例項物件指向不同的記憶體地址,也就是說兩次例項化得到的是兩個不同的物件.

為什麼需要單例模式?

要弄清楚為什麼需要單例模式, 首先需要知道單例模式提供了哪些優秀的特性?

單例模式提供的最為優秀的特性就是:單例模式可以允許你在程式的任何地方訪問某個特定的物件

通過單例設計模式, 你可以在不定義全域性變數的情況下,在程式的任何地方訪問你所指定的物件,單例模式所提供的功能和全域性變數是一樣的, 但是通過單例模式設計, 你就可以在無需犧牲程式碼可讀性和安全性的前提下完成和全域性變數完全一樣的功能. 單例模式吸收了全域性變數的優點摒棄了全域性變數的缺點,是替代可惡全域性變數不二的選擇.

在上面的例子中我們可以看到無論例項化多少次ClassA得到的都是同一個物件, 如果這個類處於一個比較大的工程中,在這個工程中的任何位置例項化ClassA得到的都是同一個物件,這不就是全域性變數嗎, 但是和全域性變數不同的是通過單例模式產生物件的程式碼更加的易讀,而且這種物件導向的程式設計方式可以確保ClassA所產生的物件只能被物件自身的方法所操作, 這樣就更加的安全, 而且你可以通過獲取例項的方法對返回物件的行為進行更多的限制.

為什麼需要單例模式? 本質上是因為人們需要全域性變數,需要一個更加好用更加安全的全域性變數, 單例模式的出現解決了全域性變數的現有問題, 所以人們才需要單例模式

單例模式和全域性變數的區別?

單例模式像極了全域性變數, 但是單例模式畢竟不是實現全域性變數, 除了上述所說的異同點之外, 通過單例模式產生的物件和全域性變數還有一個明顯的區別就是全域性變數一旦定義就絕對不會再發生改變, 但是單例模式雖然說每次返回的都是一個固定的物件, 但這個固定的物件還是可以通過單例類自身的一些方法去更改的,所以單例模式產生的物件和全域性變數比起來只能說是相對固定的.

單例模式如何實現?

任何一門語言要想實現單例模式,可能都有很多的實現方法,但是實現思路大同小異,肯定都是在第一次生成例項的時候就直接把例項給儲存到某個地方,然後在下一次例項化的時候直接返回這個事先被儲存起來的例項,而不是重新去例項化返回一個新的例項.

基於裝飾器的實現

Python實現單例模式一個比較優雅的實現方式就是通過裝飾器去實現,如下所示:

def singleton(cls):
    instances = {}
    def getinstance(*args,**kwargs):
        if cls not in instances:
            instances[cls] = cls(*args,**kwargs)
        return instances[cls]
    return getinstance

@singleton
class ClassA:
    pass

@singleton
class ClassB:
    pass

class ClassC:
    pass

aa=ClassA()
aaa=ClassA()

bb=ClassB()
bbb=ClassB()

cc=ClassC()
ccc=ClassC()

上面的例子我們可以看到singleton是一個裝飾器函式, 通過閉包的原理讓其內部的 instances 變數的生命週期和全域性變數等同,然後把被裝飾的類第一次例項化生成的物件直接儲存在instances中,在取物件的時候直接從在instances字典中找到事先儲存好的物件返回,就是通過這樣的方式實現單例的.

單例模式的實現方式還有很多種: 比如通過類屬性實現, 通過元類實現等多種方式, 甚至每一種實現可能都有自己特定的應用場景, 但是我覺得通過裝飾器實現最為優雅, 本著少就是多的原則, 其他的實現方式我就不再贅述, 如果對其他的實現方式感興趣可以在早睡蟒公眾號後臺回覆跬蟒加我微信(備註好公司崗位)交流溝通.

如果感覺本篇內容還不錯,微信的朋友請點個在看和贊,其他平臺的朋友可以(近距離)掃描下方的二維碼關注我的公眾號 早睡蟒更多優質原創無廣告內容等你來看.

相關文章