設計模式之單例模式(一)


這篇我們學習的是單例模式,相信很多朋友都或多或少使用過這個模式。很多設計模式的入門,都把單例模式作為第一個的,但是因為我們是跟着書本學習,所以放在了第五個里面。那么,你使用過的單例模式是怎么樣的呢?懶漢式?餓漢式?雙重校驗?靜態?

先來看下定義,單例模式(Singleton Pattern):用來創建獨一無二的,只能有一個實例的對象的入場券。而且,單例模式的類圖是所有設計模式中最簡單的,事實上只有一個類。但是,盡管從類的設計上來說簡單,實現上還是會遇見相當多的波折噢。

單例模式有什么用處?

有些對象其實我們只需要一個,比方說:線程池、緩存、對話框、處理偏好設置和注冊表對象、日志對象等。事實上,這些對象只能以一個實例,如果制造出多個實例,就會導致許多問題的產生,例如:程序的行為異常、資源使用過量,或者就是不一致的結果。

剖析經典的單例模式實現

我們先來看下經典的單例模式的實現代碼:

public class Singleton {

	private static Singleton uniqueInstance;
	
	private Singleton() {}
	
	public static Singleton getInstance() {
		if (uniqueInstance == null) {
			uniqueInstance = new Singleton();
		}
		return uniqueInstance;
	}
}
  • 利用一個靜態變量來記錄Singleton類的唯一實例
  • 把構造器聲明為私有化,只有Singleton類才可以調用構造器
  • 用getInstance()方法實例化對象,並返回這個實例

再仔細看下getInstance()方法,這里需要着重描述下。

  1. uniqueInstance 擁有一個“實例”,而且是一個靜態變量
  2. 如果uniqueInstance是空的,表示還沒有創建實例
  3. 如果不存在,我們就利用私有的構造器產生一個Singleton實例並把它賦值到uniqueInstance靜態變量中。請注意,如果我們不需要這個實例,他就永遠不會產生。這就是“延遲實例化”(lazy instaniaze)
  4. 如果uniqueInstance不是null,就表示之前已經創建過對象,我們就直接返回
  5. 當執行到return語句,表示我們已經有實例,並將uniqueInstance當返回值

如果沒有單例模式,這里有一個代碼寫的很小心的例子,看完你肯定會感受到單例模式的重要性。
巧克力工廠

上圖中的公司有意識地防止不好的事情發生,對吧。但是,如果防不勝防,同事存在兩個ChocolateBoiler實例,可能將發生很糟糕的事情。那么,如果有過個ChocolateBoiler實例存在,可能發生什么嚴重的事情呢?咋這個例子上,就是會產生資源的浪費,原料的溢出等等。

那么,你能根據經典的單例模式,寫出這個巧克力工廠的單例模式嗎?我們晚點揭曉。

定義單例模式

單例模式:確保一個類只有一個實例,並提供一個全局訪問點。

這定義一點兒都不讓人吃驚,但是讓我們更深入一點兒

  • 到底怎么回事?我們正在把某個類設計成自己管理的一個單獨實例,同時也避免其他類再自行產生實例。要想取得單例實例,通過單例類是唯一的途徑
  • 我們也提供對這個實例的全局訪問點:當你需要實例時,向類查詢,他會返回單個實例。前面的例子利用延遲實例化的方式創建單例,這種做法對資源敏感的對象特別重要。

那我們來看看單例的類圖:

你看吧,之前就說過,這個單例模式只有一個類圖,是不是很簡單呢?仔細看看他吧。

但是,這些都只是單線程模式下的單例模式,參考上面這個巧克力工廠,如果是多線程模式下的單例,那又會是什么樣的呢?經典的單例模式,能確保你在單線程下不出問題,但是,我們想要讓人家效率更高,產量更大,勢必需要多線程?

那么,請屏幕前的你,先好好想想,我們下次學習的時候,通過JVM原理,把這個煩惱給解決了。今天的學習就先到這里啦。

愛生活,愛學習,愛感悟,愛挨踢


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM