天天看點

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

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

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

有些對象其實我們隻需要一個,比方說:線程池、緩存、對話框、處理偏好設定和系統資料庫對象、日志對象等。事實上,這些對象隻能以一個執行個體,如果制造出多個執行個體,就會導緻許多問題的産生,例如:程式的行為異常、資源使用過量,或者就是不一緻的結果。

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

利用一個靜态變量來記錄Singleton類的唯一執行個體

把構造器聲明為私有化,隻有Singleton類才可以調用構造器

用getInstance()方法執行個體化對象,并傳回這個執行個體

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

uniqueInstance 擁有一個“執行個體”,而且是一個靜态變量

如果uniqueInstance是空的,表示還沒有建立執行個體

如果不存在,我們就利用私有的構造器産生一個Singleton執行個體并把它指派到uniqueInstance靜态變量中。請注意,如果我們不需要這個執行個體,他就永遠不會産生。這就是“延遲執行個體化”(lazy instaniaze)

如果uniqueInstance不是null,就表示之前已經建立過對象,我們就直接傳回

當執行到return語句,表示我們已經有執行個體,并将uniqueInstance當傳回值

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

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

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

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

單例模式:確定一個類隻有一個執行個體,并提供一個全局通路點。

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

到底怎麼回事?我們正在把某個類設計成自己管理的一個單獨執行個體,同時也避免其他類再自行産生執行個體。要想取得單例執行個體,通過單例類是唯一的途徑

我們也提供對這個執行個體的全局通路點:當你需要執行個體時,向類查詢,他會傳回單個執行個體。前面的例子利用延遲執行個體化的方式建立單例,這種做法對資源敏感的對象特别重要。

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

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

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

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

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

繼續閱讀