?**生活中的單例**
中國(China),位于東亞,是一個以華夏文明為主體、中華文化為基礎,以漢族為主要民族的統一多民族國家,通用漢語。中國疆域內的各個民族統稱為中華民族,龍是中華民族的象征。古老的中國憑借自身的發展依舊美麗的屹立于東方民族之林,閃耀著她動人的光彩,世界上只有一個中國,任何部分都是祖國不可分割的一部分,今天我們的設計模式就從偉大的祖國開始說起---單例模式。
**詳解單例模式**
單例模式是什么?跟我們的祖國有著怎樣的關系呢?首先我們來看一下單例,從“單例”字面意思上理解為—一個類只有一個實例,所以單例模式也就是保證一個類只有一個實例的一種實現方法。官方定義:確保一個類只有一個實例,并提供一個全局訪問點。在學習的過程中,我們需要把握三個主要的關鍵點,一、某個類只能有一個實例;二、它必須自行創建這個實例;三、它必須自行向整個系統提供這個實例。來看一下單例模式的結構圖:
? ? ? ?
? ? ? ??
**實現方法**
一個類能返回對象一個引用(永遠是同一個)和一個獲得該實例的方法(必須是靜態方法,通常使用getInstance這個名稱);當我們調用這個方法時,如果類持有的引用不為空就返回這個引用,如果類保持的引用為空就創建該類的實例并將實例的引用賦予該類保持的引用;同時我們還將該類的構造函數定義為私有方法,這樣其他處的代碼就無法通過調用該類的構造函數來實例化該類的對象,只有通過該類提供的靜態方法來得到該類的唯一實例。
**代碼實現**
**第一版(基本代碼)**
? ? ?
~~~
using?System;????
using?System.Collections.Generic;????
using?System.Linq;????
using?System.Text;????
????
namespace?單例模式基本模型????
{????
????class?Program????
????{????
????????//客戶端????
????????static?void?Main(string[]?args)????
????????{????
????????????Singleton?Instance1?=?Singleton.GetInstance();????
????????????Singleton?Instance2?=?Singleton.GetInstance();????
????
????????????if?(Instance1?==?Instance2)????
????????????{????
????????????????Console.WriteLine("兩個實例是一模一樣的實例。");????
????????????}????
????
????????}????
????}????
????class?Singleton????
????{????
????????private?static?Singleton?instance;????
????
????????//構造方法采用private,外界便無法用new創建該類的實例????
????????private?Singleton()????
????????{?}????
????
????????//該方法提供一個獲得該類實例的全局訪問點,是唯一的????
????????public?static?Singleton?GetInstance()????
????????{????
????????????//如果實例不存在,則返回一個新實例,否則返回原實例。????
????????????if?(instance?==?null)????
????????????{????
????????????????instance?=?new?Singleton();????
????????????}????
????????????return?instance;????
????????}????
????}????
}????
~~~
但是上述代碼存在一些缺點,線程不安全,多線程情況下,多個線程同時訪問Singleton,調用GetInstance()方法,同時判斷instance==null,得到真值,導致創建多個實例,這不符合單例模式的基本原則。那我們要怎么辦捏,為了解決以上缺點,我們來看改進的代碼(一下版本的)
**第二版(多線程時的單例)**
~~~
class?Singleton????
????{????
????????private?static?Singleton?instance=null;????
????????//創建一個靜態只讀的進程輔助對象????
????????private?static?readonly?object?ProgressLock?=?new?object();????
????
????????//構造方法采用private,外界便無法用new創建該類的實例????
????????private?Singleton()????
????????{?}????
????
????????//該方法提供一個獲得該類實例的全局訪問點,是唯一的????
????????public?static?Singleton?GetInstance()????
????????{????
????????????lock?(ProgressLock)????
????????????{????
????????????????????
????????????????if?(instance?==?null)????
????????????????{????
????????????????????instance?=?new?Singleton();????
????????????????}????
????????????}????
???????????????
????????????return?instance;????
????????}????
????}????
~~~
每次調用GetInstance()方法都需要lock,這種做法是會影響性能的,所以我們需要對這個類進行改良。
**第三版(雙重鎖定)**
~~~
class?Singleton????
????{????
????????private?static?Singleton?instance=null;????
????????//創建一個靜態只讀的進程輔助對象????
????????private?static?readonly?object?ProgressLock?=?new?object();????
????
????????//構造方法采用private,外界便無法用new創建該類的實例????
????????private?Singleton()????
????????{?}????
????
????????//該方法提供一個獲得該類實例的全局訪問點,是唯一的????
????????public?static?Singleton?GetInstance()????
????????{????
????????????if?(instance?==?null)????
????????????{????
????????????????lock?(ProgressLock)????
????????????????{????
????
????????????????????if?(instance?==?null)????
????????????????????{????
????????????????????????instance?=?new?Singleton();????
????????????????????}????
????????????????}????
????????????}????
?????????????????????
????????????return?instance;????
????????}????
????}????
~~~
上述構造方式只有在實例未被創建的時候才加鎖,避免了每次調用GetInstance()方法都加鎖損失性能的問題。但是相對于后面的做法,她仍然有著美中不足的地方。
**第四版(靜態初始化)**
~~~
//sealed關鍵字防止派生????
????public?sealed?class?Singleton????
????{????
????????//在第一次引用類的成員時創建實例,公共語言運行庫負責處理變量的初始化????
????????private?static?readonly?Singleton?instance=new?Singleton();????
???????????
????????//構造方法采用private,外界便無法用new創建該類的實例????
????????private?Singleton()????
????????{?}????
????
????????public?static?Singleton?GetInstance()????
????????{????
????????????return?instance;????
????????}????
????}????
~~~
這種方式是在自己被加載時就將自己實例化,稱為餓漢式。由于有.NetFramework 進行初始化,所以我們對實例化機制的控制權較少,沒辦法和其他實現一樣實現延遲初始化。在上面三種形式中,您能夠在實例化之前使用非默認的構造函數或執行其他任務。
**第五版(完全延遲加載實例化)**
~~~
public?sealed?class?Singleton?????
?{????
????????private?Singleton()????
????????{????
????????}????
????????public?static?Singleton?GetInstance()????
????????{????
????????????return?Nested.instance;????
????????}????
????????class?Nested????
????????{????
????????????static?Nested()????
????????????{????
????????????}????
????????????internal?static?readonly?Singleton?instance?=?new?Singleton();????
????????}????
????}????
~~~
? ? ? ? ? ?
**寫在后面的話**
前三版編程方法,因為會面臨多線程訪問安全的問題,需要做雙重鎖定這樣的處理才可以保證安全,但能夠在實例化之前使用非默認的構造函數或執行其他任務,第四版(靜態初始化方式)是類一加載就實例化的對象,占用系統資源,所以到底實用哪一種方式,視具體情況而定.