前言
單例模式可能是最簡單的設計模式,單例是非常通用的對象。讓你能夠保證一個類只有一個實例, 並提供一個訪問該實例的全局節點。
我們可以將船的船長視為單例模式的現實生活中的例子。在船上,他是負責人。他負責重要的決定,由於這一責任,他收到了一些請求。
如前所述,單例模式的一個用例是創建一個維護程序全局狀態的單個對象。其他可能的用例如下:
- 控制對共享資源的並發訪問;例如,管理與數據庫的連接的對象類
- 橫向的服務或資源,因為它可以從應用程序的不同部分或由不同的用戶訪問並完成其工作;例如,日志記錄系統或實用程序核心的類
class Singleton:
"""Definition of a Singleton object."""
singleton_instance = None
def __init__(self):
"""
Override the initialization
mechanism, returning only the single instance.
"""
...
@staticmethod
def get_singleton():
"""
Method for fetching the Singleton instance.
Is static so that it can be accessed everywhere.
"""
...
@staticmethod
def update_singleton(val):
"""
Method for setting value of Singleton instance.
Is static so that it can be accessed everywhere.
"""
...
存儲在 Singleton 實例中的數據是任意的。重要的是,無論數據,呼叫者和范圍如何,Singleton 對象都會返回同一實例。這使得單元在實現諸如全局設置或運行配置之類的內容時有用。
單例例子
使用下面的代碼片段來播放 Active Singleton 實現。嘗試用數據結構(例如字典)替換可變Singleton_instance,並查看 Getter 和 Setter 的實現如何更改。嘗試編寫一些共享 Singleton 實例的功能。
class Singleton:
"""Definition of a Singleton object."""
# Maintain state of Singleton
singleton_instance = None
def __init__(self):
"""Override the initialization mechanism."""
if Singleton.singleton_instance is None:
Singleton.singleton_instance = self
@staticmethod
def get_singleton():
"""
Method for fetching the Singleton instance.
Is static so that it can be accessed everywhere.
"""
if Singleton.singleton_instance is None:
Singleton() # Call __init__ to initialize instance
return Singleton.singleton_instance
@staticmethod
def update_singleton(val):
"""
Method for setting value of Singleton instance.
Is static so that it can be accessed everywhere.
"""
if Singleton.singleton_instance is None:
Singleton() # Call __init__ to initialize instance
Singleton.singleton_instance = val
Singleton.update_singleton("Michael")
print("Value in Singleton instance is: " + Singleton.get_singleton())
Singleton() # Try to create a new Singleton instance
print("Value in Singleton instance is STILL: " + Singleton.get_singleton())
單例模式也可以通過使單例類使用元類(其類型,具有先前定義的元類)來實現。根據需要,元類的
__call__()
方法保存的代碼可確保只能創建類的一個實例:
class SingletonMeta(type):
"""
The Singleton class can be implemented in different ways in Python. Some
possible methods include: base class, decorator, metaclass. We will use the
metaclass because it is best suited for this purpose.
"""
_instances = {}
def __call__(cls, *args, **kwargs):
"""
Possible changes to the value of the `__init__` argument do not affect
the returned instance.
"""
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_business_logic(self):
"""
Finally, any singleton should define some business logic, which can be
executed on its instance.
"""
# ...
if __name__ == "__main__":
# The client code.
s1 = Singleton()
s2 = Singleton()
if id(s1) == id(s2):
print("Singleton works, both variables contain the same instance.")
else:
print("Singleton failed, variables contain different instances.")
單例模式優缺點
優點:
- 你獲得了一個指向該實例的全局訪問節點。
- 僅在首次請求單例對象時對其進行初始化。
缺點:
- 違反了單一職責原則。 該模式同時解決了兩個問題。
- 單例模式可能掩蓋不良設計, 比如程序各組件之間相互了解過多等。
- 該模式在多線程環境下需要進行特殊處理, 避免多個線程多次創建單例對象。
- 單例的客戶端代碼單元測試可能會比較困難, 因為許多測試框架以基於繼承的方式創建模擬對象。 由於單例類的構造函數是私有的, 而且絕大部分語言無法重寫靜態方法, 所以你需要想出仔細考慮模擬單例的方法。 要麼干脆不編寫測試代碼, 或者不使用單例模式。
參考鏈接: