關於單例模式的定義和實現

前言

摘自:《設計模式之禪》 這本書

單例模式的定義:

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

一個好理解的例子:

自從秦始皇確立了皇帝這個位置以後,同一時期基本上就只有一個人孤零零地坐在這個位置。這種情況下臣民們也好處理,大家叩拜、談論的時候只要提及皇帝,每個人都知道指的是誰,而不用在皇帝前面加上特定的稱呼,如張皇帝、李皇帝。

這一個過程反應到設計領域就是,要求一個類只能生成一個對象(皇帝),所有對象對它的依賴都是相同的,因爲只有一個對象,大家對它的脾氣和習性都非常瞭解,建立健壯穩固的關係,

單例模式的實現

1、單例模式的定義裏面已經寫清楚了,首先我們要確保一個類只有一個實例

一個類只能產生一個對象,該怎麼實現呢?對象產生是通過new關鍵字完成的(當然也有其他方式,比如對象拷貝、反射等),這個怎麼控制呀,但是大家別忘記了構造函數,使用new關鍵字創建對象時,都會根據輸入的參數調用相應的構造函數,如果我們把構造函數設置爲private私有訪問權限不就可以禁止外部創建對象了嗎

具體代碼如下:

    public sealed class Singleton
    {
        // 禁止外部創建對象
        private Singleton()
        {

        }

    }

此時在其他類裏面new Singleton()就會報錯
在這裏插入圖片描述
2、然後需要 可以 自行實例化並向整個系統提供這個實例。

	// 一個簡單的單例模式代碼
 	public sealed class Singleton
    {
    	private static readonly Singleton singleton = new Singleton();
        private Singleton()
        {
        }
		// 提供單例實例化之後的對象
        public static Singleton Instance ()
        {
       		 return singleton;
        }
    }

單例模式寫法進階:https://www.cnblogs.com/leolion/p/10241822.html
這裏用到了lazy,對象的加載是需要消耗時間的,特別是對於大對象來說消耗的時間。
NET 4.0中加入了lazy (延遲對象加載.),lazy可以實現對象的延遲加載。在第一次使用該對象時再對其進行初始化,如果沒有用到則不需要進行初始化。
這樣的話,使用延遲初始化就提高程序的效率,從而使程序佔用更少的內存。聽起來就很適合單例模式

 	public sealed class Singleton
    {
        private static readonly Lazy<Singleton> lazy =
            new Lazy<Singleton>(() => new Singleton());

        public static Singleton Instance { get { return lazy.Value; } }

        // 禁止外部創建對象
        private Singleton()
        {

        }

        public static void Say()
        {
            Console.WriteLine("Hello World");
        }
    }
單例模式的優缺點

單例模式的優點:

  1. 由於單例模式在內存中只有一個實例,減少了內存開支,特別是一個對象需要頻繁地創建、銷燬時,而且創建或銷燬時性能又無法優化,單例模式的優勢就非常明顯。所以上述的Lazy延遲加載無疑很適合用於單例模式下類的自行實例化
  2. 由於單例模式只生成一個實例,所以減少了系統的性能開銷,當一個對象的產生需要比較多的資源時,如讀取配置、產生其他依賴對象時,則可以通過在應用啓動時直接產生一個單例對象,然後用永久駐留內存的方式來解決(在Java
    EE中採用單例模式時需要注意JVM垃圾回收機制)。
  3. 單例模式可以避免對資源的多重佔用,例如一個寫文件動作,由於只有一個實例存在內存中,避免對同一個資源文件的同時寫操作。
  4. 單例模式可以在系統設置全局的訪問點,優化和共享資源訪問,例如可以設計一個單例類,負責所有數據表的映射處理。

單例模式的缺點:

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

在一個系統中,要求一個類有且僅有一個對象,如果出現多個對象就會出現“不良反應”,可以採用單例模式,具體的場景如下:

  1. 要求生成唯一序列號的環境;
  2. 在整個項目中需要一個共享訪問點或共享數據,例如一個Web頁面上的計數器,可以不用把每次刷新都記錄到數據庫中,使用單例模式保持計數器的值,並確保是線程安全的;
  3. 創建一個對象需要消耗的資源過多,如要訪問IO和數據庫等資源;
  4. 需要定義大量的靜態常量和靜態方法(如工具類)的環境,可以採用單例模式(當然,也可以直接聲明爲static的方式)。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章