模式動機
對於系統中的某些類來講,只有一個實例很重要,例如,一個系統中能夠存在多個打印任務,可是隻能有一個正在工做的任務;一個系統只能有一個窗口管理器或文件系統;一個系統只能有一個計時工具或ID(序號)生成器。
如何保證一個類只有一個實例而且這個實例易於被訪問呢?定義一個全局變量能夠確保對象隨時均可以被訪問,但不能防止咱們實例化多個對象。
一個更好的解決辦法是讓類自身負責保存它的惟一實例。這個類能夠保證沒有其餘實例被建立,而且它能夠提供一個訪問該實例的方法。這就是單例模式的模式動機。數據庫
模式定義
單例模式(Singleton Pattern):單例模式確保某一個類只有一個實例,並且自行實例化並向整個系統提供這個實例,這個類稱爲單例類,它提供全局訪問的方法。
單例模式的要點有三個:一是某個類只能有一個實例;二是它必須自行建立這個實例;三是它必須自行向整個系統提供這個實例。單例模式是一種對象建立型模式。單例模式又名單件模式或單態模式。
Singleton Pattern: Ensure a class has only one instance and provide a global point of access to it.
Frequency of use: medium high
UML圖
ide
模式結構
單例模式包含以下角色:
Singleton:單例函數
模式分析
單例模式的目的是保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。單例模式包含的角色只有一個,就是單例類——Singleton。單例類擁有一個私有構造函數,確保用戶沒法經過new關鍵字直接實例化它。除此以外,該模式中包含一個靜態私有成員變量與靜態公有的工廠方法,該工廠方法負責檢驗實例的存在性並實例化本身,而後存儲在靜態成員變量中,以確保只有一個實例被建立。工具
在單例模式的實現過程當中,須要注意以下三點:
單例類的構造函數爲私有;
提供一個自身的靜態私有成員變量;
提供一個公有的靜態工廠方法。性能
實例:身份證號碼
在現實生活中,居民身份證號碼具備惟一性,同一我的不容許有多個身份證號碼,第一次申請身份證時將給居民分配一個身份證號碼,若是以後由於遺失等緣由補辦時,仍是使用原來的身份證號碼,不會產生新的號碼。
Singleton.csspa
namespace SingletonPattern { class Singleton { private static Singleton instance; //構造方法讓其private,這就堵死了外界利用new建立此類實例的可能 private Singleton() { } //此方法是得到本類實例的惟一全局訪問點 public static Singleton GetInstance() { //若實例不存在,則new一個新實例,不然返回已有的實例 if (instance == null) { instance = new Singleton(); } return instance; } } }
客戶端代碼設計
using System; namespace SingletonPattern { class Program { static void Main(string[] args) { Singleton s1 = Singleton.GetInstance(); Singleton s2 = Singleton.GetInstance(); if (s1 == s2) { Console.WriteLine("兩個對象是相同的實例"); } Console.Read(); } } }
單例模式的優勢
提供了對惟一實例的受控訪問。由於單例類封裝了它的惟一實例,因此它能夠嚴格控制客戶怎樣以及什麼時候訪問它,併爲設計及開發團隊提供了共享的概念。
因爲在系統內存中只存在一個對象,所以能夠節約系統資源,對於一些須要頻繁建立和銷燬的對象,單例模式無疑能夠提升系統的性能。
容許可變數目的實例。咱們能夠基於單例模式進行擴展,使用與單例控制類似的方法來得到指定個數的對象實例。3d
單例模式的缺點
因爲單例模式中沒有抽象層,所以單例類的擴展有很大的困難。
單例類的職責太重,在必定程度上違背了「單一職責原則」。由於單例類既充當了工廠角色,提供了工廠方法,同時又充當了產品角色,包含一些業務方法,將產品的建立和產品的自己的功能融合到一塊兒。
濫用單例將帶來一些負面問題,如爲了節省資源將數據庫鏈接池對象設計爲單例類,可能會致使共享鏈接池對象的程序過多而出現鏈接池溢出;如今不少面嚮對象語言(如Java、C#)的運行環境都提供了自動垃圾回收的技術,所以,若是實例化的對象長時間不被利用,系統會認爲它是垃圾,會自動銷燬並回收資源,下次利用時又將從新實例化,這將致使對象狀態的丟失。code
模式適用環境
在如下狀況下可使用單例模式:
系統只須要一個實例對象,如系統要求提供一個惟一的序列號生成器,或者須要考慮資源消耗太大而只容許建立一個對象。
客戶調用類的單個實例只容許使用一個公共訪問點,除了該公共訪問點,不能經過其餘途徑訪問該實例。
在一個系統中要求一個類只有一個實例時才應當使用單例模式。反過來,若是一個類能夠有幾個實例共存,就須要對單例模式進行改進,使之成爲多例模式。對象