Deepin 安裝 tomcat
阿新 • • 發佈:2020-07-15
前言
單例模式應該是所有接觸的設計模式初學者第一個聽過的設計模式,這個模式應該是所有設計模式中最簡單的一個模式了。值得注意的是,許多開發者將單例模式視為一種反模式,因此單例模式在 Python 中的使用頻率現在越來越少了。
反模式(英文:Anti-patterns或pitfalls), 是指用來解決問題的帶有共同性的不良方法。它們已經經過研究並分類,以防止日後重蹈覆轍,並能在研發尚未投產時辨認出來。軟體開發中公認的反模式
意圖
UML 圖
應用場景
單例模式最常使用的場景就是連線資料庫以及日誌等等,單例模式使用的場景通常有以下幾個特點
程式碼
簡單單例模式
class SingletonMeta(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: instance = super().__call__(*args, **kwargs) cls._instances[cls] = instance return cls._instances[cls] class Singleton(metaclass=SingletonMeta): def some_action(self): pass if __name__ == "__main__": s1 = Singleton() s2 = Singleton() if id(s1) == id(s2): print("Singleton works") else: print("Singleton failed")
看一下輸出:
Singleton works
執行緒安全單例模式
上面的單例模式可能會在多執行緒環境中出錯,所以為了解決這個問題,我們將單例模式再升級一下
from threading import Lock, Thread class SingletonMeta(type): _instances = {} _lock: Lock = Lock() def __call__(cls, *args, **kwargs): with cls._lock: if cls not in cls._instances: instance = super().__call__(*args, **kwargs) cls._instances[cls] = instance return cls._instances[cls] class Singleton(metaclass=SingletonMeta): value: str = None def __init__(self, value: str) -> None: self.value = value def some_action(self): pass def test_singleton(value: str) -> None: singleton = Singleton(value) print(singleton.value) if __name__ == "__main__": # 由於是單例模式,預期兩個執行緒輸出的結果應該一樣,都是第一個 FOO process1 = Thread(target=test_singleton, args=("FOO",)) process2 = Thread(target=test_singleton, args=("BAR",)) process1.start() process2.start()
看一下輸出結果:
FOO
FOO
總結
單例模式優缺點
優點
缺點
- 違反了單一職責原則。
- 單例模式可能掩蓋不良設計, 可能會隱藏類之間的依賴關係。
- 該模式在多執行緒環境下需要進行特殊處理, 避免多個執行緒多次建立單例物件。
- 單例的客戶端程式碼單元測試可能會比較困難, 因為許多測試框架以基於繼承的方式建立模擬物件。 由於單例類的建構函式是私有的, 而且絕大部分語言無法重寫靜態方法。
- 單例不支援有引數的建構函式,比如我們建立一個連線池的單例物件,我們沒法通過引數來指定連線池的大小。