《設計模式之禪》之單例模式

  • 2019 年 11 月 7 日
  • 筆記

一、單例模式定義

確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例。

二、單例模式的應用

1.單例模式的優點

  • 由於單例模式再記憶體中只有一個實例,減少了記憶體開支,特別是一個對象需要頻繁地創建、銷毀時,而且創建或銷毀時性能又無法優化,單例模式的優勢就非常明顯;
  • 由於單例模式只生成一個實例,所以減少了系統的性能開銷,當一個對象的產生需要比較多的資源時,如讀取配置、產生其他依賴對象時,則可以通過在應用啟動時直接產生一個單例對象,然後用永久駐留記憶體的方式解決(在JavaEE中採用單例模式時需要注意JVM垃圾回收機制);
  • 單例模式可以避免對資源的多重佔用,例如一個寫文件動作,由於只有一個實例存在記憶體中,避免對同一個資源文件的同時寫操作;
  • 單例模式可以在系統設置全局的訪問點,優化和共享資源訪問,例如可以設計一個單例類,負責所有數據表的映射處理;

2.單例模式的缺點

  • 單例模式一般沒有介面,擴展很困難,若要擴展,除了修改程式碼基本上沒有第二種途徑可以實現。單例模式為什麼不能增加介面呢?因為介面對單例模式是沒有意義的,它要求”自行實例化”,並且提供單一實例、介面或抽象類是不可能被實例化的。當然,在特殊情況下,單例模式可以實現介面、被繼承等,需要在系統開發中根據環境判斷;
  • 單例模式對測試是不利的。在並行開發環境中,如果單例模式沒有完成,是不能進行測試的,沒有介面也不能使用mock的方式虛擬一個對象;
  • 單例模式與單一職責原則有衝突。一個類應該只實現一個邏輯,而不關心它是否是單例的,是不是要單例取決於環境,單例模式把”要單例”和業務邏輯融合在一個類中;

3.單例模式的使用場景

  • 要求生成唯一序列號的環境;
  • 在整個項目中需要把一個共享訪問點或共享數據,例如一個Web頁面上的計數器,可以不用把每次刷新都記錄到資料庫中,使用單例模式保持計數器的值,並確保是執行緒安全的;
  • 創建一個對象需要消耗的資源過多,如要訪問IO和資料庫等資源;
  • 需要定義大量的靜態常量和靜態方法(如工具類)的環境,可以採用單例模式(當然,也可以直接聲明為static的方式);

三、最佳實踐

單例模式是23個模式中比較簡單的模式,應該也非常廣泛,如在Spring中,每個Bean默認就是單例的,這樣做的優點是Spring容器可以管理這些Bean的生命期,決定什麼時候創建出來,什麼時候銷毀,銷毀的時候要如何處理,等等。如果採用非單例模式,則Bean初始化後的管理交由J2EE容器,Spring容器不再跟蹤管理Bean的生命周期。

程式碼例子:https://github.com/developers-youcong/DesignPatternPractice/tree/master/Singleton