1. 程式人生 > 實用技巧 >Deepin 安裝 tomcat

Deepin 安裝 tomcat

前言

單例模式應該是所有接觸的設計模式初學者第一個聽過的設計模式,這個模式應該是所有設計模式中最簡單的一個模式了。值得注意的是,許多開發者將單例模式視為一種反模式,因此單例模式在 Python 中的使用頻率現在越來越少了。

反模式(英文:Anti-patterns或pitfalls), 是指用來解決問題的帶有共同性的不良方法。它們已經經過研究並分類,以防止日後重蹈覆轍,並能在研發尚未投產時辨認出來。軟體開發中公認的反模式

意圖

保證一個類僅有一個例項,並提供一個訪問它的全劇訪問點。

UML 圖

簡單看一下單例模式的 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

總結

單例模式優缺點

優點

  • 你可以保證一個類只有一個例項。
  • 你獲得了一個指向該例項的全域性訪問節點。
  • 僅在首次請求單例物件時對其進行初始化。

缺點

  • 違反了單一職責原則
  • 單例模式可能掩蓋不良設計, 可能會隱藏類之間的依賴關係。
  • 該模式在多執行緒環境下需要進行特殊處理, 避免多個執行緒多次建立單例物件。
  • 單例的客戶端程式碼單元測試可能會比較困難, 因為許多測試框架以基於繼承的方式建立模擬物件。 由於單例類的建構函式是私有的, 而且絕大部分語言無法重寫靜態方法。
  • 單例不支援有引數的建構函式,比如我們建立一個連線池的單例物件,我們沒法通過引數來指定連線池的大小。