設計模式之單例模式

GOF對單例模式的定義:保證類僅有一個實例,並提供一個訪問它的全局訪問點。

單例模式的的基本代碼比較簡單

/**
 * 
 * @author ricardo
 * @Time 下午10:40:11
 * @Function:定義單例模式類
 *
 */
public class Singleton {
	private static Singleton singleton;
	private Singleton() {}
	
	public static Singleton GetInstance() {
		if(singleton == null)
			singleton = new Singleton();
		return singleton;
	}
}

單例模式中,Singleton類封裝了它的唯一實例,以此來控制第三方如何以及何時訪問它。也就是對唯一實例的受限訪問。

單例模式的應用很簡單,舉個例子來說明,現在實行一夫一妻制,假設我們現在有一個Wife/Husband 類

/**
 * 
 * @author ricardo
 * @Time 下午10:17:02
 * @Function:姑娘
 *
 */
public class Wife {
	public void Show() {
		System.out.println("秀外慧中的姑娘");
	}
	public void Marry() {
		System.out.println("姑娘要嫁人了");
	}
}
/**
 * 
 * @author ricardo
 * @Time 下午10:18:22
 * @Function:男孩紙
 *
 */
public class Husband {
	private Wife myWife = null;
	
	public void ChooseWife() {		
		if(myWife == null)
			myWife = new Wife();
		myWife.Show();
	}
	
	public void GetMarry() {		
		if(myWife == null)
			myWife = new Wife();
		myWife.Marry();
	}
}	
/**
 * 
 * @author ricardo
 * @Time 下午10:20:35
 * @Function:客戶端代碼
 *
 */
public class First {
	public static void main(String[] args) {
		Husband husband = new Husband();		
		System.out.println("男孩紙喜歡上一個姑娘");
		husband.ChooseWife();
		System.out.println("姑娘被男孩子打動了");
		husband.GetMarry();		
	}
}
運行截圖:


但是這樣會有個問題,假設男孩紙的媽媽想見見兒媳,於是:

public class Mother {
	Wife daughter = null;
	public void CheckDaughterInLaw() {		
		if(daughter == null)
			daughter = new Wife();
		daughter.Show();
	}
}
這裏母親會實例化一個Wife出來,很明顯,這裏出來的並不是男孩子心儀的姑娘了,而不實例化,則會出現空指針。so,我們使用單例來實現

/**
 * 
 * @author ricardo
 * @Time 下午10:17:02
 * @Function:姑娘
 *
 */
public class Wife {
	
	private static Wife wife;
	private Wife() {}
	
	public static Wife newInstance() {
		if(wife == null)
			wife = new Wife();
		return wife;
	}		
	public void Show() {
		System.out.println("秀外慧中的姑娘");
	}
	public void Marry() {
		System.out.println("姑娘要嫁人了");
	}
}
/**
 * 
 * @author ricardo
 * @Time 下午10:18:22
 * @Function:男孩紙
 *
 */
public class Husband {
	private Wife myWife = null;
	
	public void ChooseWife() {
		
		myWife = Wife.newInstance();
		
//		if(myWife == null)
//			myWife = new Wife();
		myWife.Show();
	}
	
	public void GetMarry() {
		myWife = Wife.newInstance();
//		if(myWife == null)
//			myWife = new Wife();
		myWife.Marry();
	}
}
public class Mother {
	Wife daughter = null;
	public void CheckDaughterInLaw() {
		daughter = Wife.newInstance();
//		if(daughter == null)
//			daughter = new Wife();
		daughter.Show();
	}
}
客戶端:

/**
 * 
 * @author ricardo
 * @Time 下午10:20:35
 * @Function:客戶端代碼
 *
 */
public class First {
	public static void main(String[] args) {
		Husband husband = new Husband();
		
		System.out.println("男孩紙喜歡上一個姑娘");
		husband.ChooseWife();
		System.out.println("姑娘被男孩子打動了");
		husband.GetMarry();
		System.out.println("母親想見見兒媳");
		Mother mother = new Mother();
		mother.CheckDaughterInLaw();
	}
}
這樣子,就會看到,姑娘只有唯一一個了。

不過如果將程序擴展一下,假設婚禮準備安排現場直播,這時候就是多線程上場的時候了,但是這樣的單例模式沒有辦法保證在不同線程進入Wife類的時候,進入myWife==null的判定,所以我們需要對Wife進行加鎖。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 
 * @author ricardo
 * @Time 下午10:17:02
 * @Function:姑娘
 *
 */
public class Wife {	
	static Lock lock = new ReentrantLock();
	private static Wife wife;
	private Wife() {}
	
	public static Wife newInstance() {
		//如果不加這個判定,每次進入都會被鎖上,將嚴重影響系統性能		
		if(wife == null) {
			lock.lock();
			//如果不加這個判定
			if(wife == null)
				wife = new Wife();
			lock.unlock();
		}
		return wife;
	}		
	public void Show() {
		System.out.println("秀外慧中的姑娘");
	}
	public void Marry() {
		System.out.println("姑娘要嫁人了");
	}
}

我們使用雙重判斷來優化系統,但是,如果僅僅相對於單例模式來說,可以利用JVM第一次加載類的時候會初始化所有靜態變量,所以可以這麼來
/**
 * 
 * @author ricardo
 * @Time 下午10:17:02
 * @Function:姑娘
 *
 */
public class Wife {
	
	static Lock lock = new ReentrantLock();
	private static Wife wife = new Wife();;
	private Wife() {}
	
	public static Wife newInstance() {		
//		if(wife == null) {
//			lock.lock();
//			if(wife == null)
//				wife = new Wife();
//			lock.unlock();
//		}
		return wife;
	}		
	public void Show() {
		System.out.println("秀外慧中的姑娘");
	}
	public void Marry() {
		System.out.println("姑娘要嫁人了");
	}
}
理解這樣的單例模式,我們也可以通過計數的方式,實現雙例模式,三例模式等需要實例化有限次的類。

以上內容,整理自劉徑舟,張玉華編著的《設計模式其實很簡單》讀書筆記,歡迎轉載.





發佈了38 篇原創文章 · 獲贊 1 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章