3.設計模式之一:單例模式【建立型模式】

建立型模式分爲如下幾種。python

  • 單例(Singleton)模式:某個類只能生成一個實例,該類提供了一個全局訪問點供外部獲取該實例,其拓展是有限多例模式。
  • 原型(Prototype)模式:將一個對象做爲原型,經過對其進行復制而克隆出多個和原型相似的新實例。
  • 工廠方法(FactoryMethod)模式:定義一個用於建立產品的接口,由子類決定生產什麼產品。
  • 抽象工廠(AbstractFactory)模式:提供一個建立產品族的接口,其每一個子類能夠生產一系列相關的產品。
  • 建造者(Builder)模式:將一個複雜對象分解成多個相對簡單的部分,而後根據不一樣須要分別建立它們,最後構建成該複雜對象。

以上 5 種建立型模式,除了工廠方法模式屬於類建立型模式,其餘的所有屬於對象建立型模式數據庫

定義與特色

單例(Singleton)模式的定義:指一個類只有一個實例,且該類能自行建立這個實例的一種模式。設計模式

例如,Windows 中只能打開一個任務管理器,這樣能夠避免因打開多個任務管理器窗口而形成內存資源的浪費,或出現各個窗口顯示內容的不一致等錯誤。緩存

在計算機系統中,還有 Windows 的回收站、操做系統中的文件系統、多線程中的線程池、顯卡的驅動程序對象、打印機的後臺處理服務、應用程序的日誌對象、數據庫的鏈接池、網站的計數器、Web 應用的配置對象、應用程序中的對話框、系統中的緩存等經常被設計成單例。安全

單例模式有 3 個特色:網絡

  1. 單例類只有一個實例對象;
  2. 該單例對象必須由單例類自行建立;
  3. 單例類對外提供一個訪問該單例的全局訪問點;

結構與實現

單例模式是設計模式中最簡單的模式之一。一般,普通類的構造函數是公有的,外部類能夠經過「new 構造函數()」來生成多個實例。多線程

可是,若是將類的構造函數設爲私有的,外部類就沒法調用該構造函數,也就沒法生成多個實例。ide

這時該類自身必須定義一個靜態私有實例,並向外提供一個靜態的公有函數用於建立或獲取該靜態私有實例。函數

單例模式的結構

單例模式的實現

Singleton 模式一般有兩種實現形式。性能

懶漢式單例

該模式的特色是類加載時沒有生成單例,只有當第一次調用 get_instance 方法時纔去建立這個單例。

class LazySingleton(object):
    __instance = None

    def __init__(self):
        """ Virtually private constructor. """
        pass

    @staticmethod
    def get_instance():
        """ Static access method. """
        if LazySingleton.__instance == None:
            LazySingleton.__instance = LazySingleton()
        return LazySingleton.__instance

s1 = LazySingleton()
s2 = LazySingleton()
print(s1._LazySingleton__instance, s2._LazySingleton__instance, end='\n')  # 未調用get_instance方法時未建立
print(s1.get_instance(), s2.get_instance(), end='\n')  # 指向同一對象
None None
<__main__.LazySingleton object at 0x0000020A56899FD0> <__main__.LazySingleton object at 0x0000020A56899FD0>

注意:若是編寫的是多線程程序,注意存在線程非安全的問題。若是保證線程安全,那麼每次訪問時都要同步,會影響性能,且消耗更多的資源,這是懶漢式單例的缺點。

餓漢式單例

該模式的特色是類一旦加載就建立一個單例,保證在調用 get_instance 方法以前單例已經存在了

class HungrySingleton(object):
    __instance = None
    def __new__(cls, *args, **kwargs):
        if cls.__instance == None:
            cls.__instance = super(HungrySingleton, cls).__new__(cls)
        return cls.__instance

    @staticmethod
    def get_instance():
        return HungrySingleton.__instance

h1 = HungrySingleton()
h2 = HungrySingleton()
print(h1._HungrySingleton__instance, h2._HungrySingleton__instance, end='\n')  # 未調用get_instance方法時已經建立
print(h1.get_instance(), h2.get_instance(), end='\n')  # 與上面一致
<__main__.HungrySingleton object at 0x0000020A568A1048> <__main__.HungrySingleton object at 0x0000020A568A1048>
<__main__.HungrySingleton object at 0x0000020A568A1048> <__main__.HungrySingleton object at 0x0000020A568A1048>

餓漢式單例在類建立的同時就已經建立好一個靜態的對象供系統使用,之後再也不改變,因此是線程安全的,能夠直接用於多線程而不會出現問題。

應用實例

【例1】用懶漢式單例模式模擬產生美國當今總統對象。

分析:在每一屆任期內,美國的總統只有一人,因此本實例適合用單例模式實現,圖所示是用懶漢式單例實現的結構圖。

class President(object):
    __instance = None

    def __init__(self):
        print("產生一個新總統")

    @staticmethod
    def get_instance():
        if President.__instance == None:
            President.__instance = President()
        else:
            print("已經有一個總統了")
        return President.__instance

    def get_name(self):
        print("特朗普是新總統")

if __name__ == '__main__':
    p1 = President.get_instance()
    p1.get_name()
    p2 = President.get_instance()
    p2.get_name()
    if p1 == p2:
        print('他們是同一人')
    else:
        print('他們不是同一人')
產生一個新總統
特朗普是新總統
已經有一個總統了
特朗普是新總統
他們是同一人

應用場景

前面分析了單例模式的結構與特色,如下是它一般適用的場景的特色。

  • 在應用場景中,某類只要求生成一個對象的時候,如一個班中的班長、每一個人的身份證號等。
  • 當對象須要被共享的場合。因爲單例模式只容許建立一個對象,共享該對象能夠節省內存,並加快對象訪問速度。如 Web 中的配置對象、數據庫的鏈接池等。
  • 當某類須要頻繁實例化,而建立的對象又頻繁被銷燬的時候,如多線程的線程池、網絡鏈接池等。

單例模式的擴展

單例模式可擴展爲有限的多例(Multitcm)模式,這種模式可生成有限個實例並保存在 ArmyList 中,客戶須要時可隨機獲取,其結構圖如圖所示。

相關文章
相關標籤/搜索