# Python設計模式 單例模式

什麼是單例模式?

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

上圖中的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字典中找到事先存儲好的對象返回,就是通過這樣的方式實現單例的.

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

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