一.需求
在遙遠(yuǎn)的山村集侯,由于交通不便慎宾,物資匱泛,很多生活必需品都供應(yīng)不足浅悉。家家戶戶都需要吃的食鹽便是如此趟据。村里有幾家雜貨店供應(yīng)日常用品,油鹽醬醋倒是都有供應(yīng)术健,但是食鹽卻是常常供不應(yīng)求汹碱,主要是因?yàn)槭雏}需要從很遠(yuǎn)的地方才可以進(jìn)貨,而由于交通不便每次又運(yùn)不了太多荞估。
時(shí)間長(zhǎng)了咳促,幾家雜貨店的老板看到了其中的商機(jī)。有的囤貨不賣勘伺,等其他幾家賣完后加價(jià)出售跪腹;有的以次充好,銷售劣質(zhì)食鹽飞醉;有時(shí)冲茸,幾家雜貨店老版甚至集體漲價(jià)。種種伎倆,到頭來吃虧的都是普通村民們轴术。
村長(zhǎng)也想過很多辦法規(guī)范食鹽銷售难衰,但是由于交通的根本問題一直得不到解決,每次嚴(yán)厲懲治后不久逗栽,雜貨店就變相漲價(jià)盖袭,道高一尺,魔高一丈彼宠■看來,必須要想一個(gè)徹底解決問題的辦法凭峡。
二.解決方案
經(jīng)過村委會(huì)討論拙已,大家想出一個(gè)好辦法:村委會(huì)出資采購(gòu)食鹽,平價(jià)銷售想罕。幾個(gè)雜貨店一看再也漲不了價(jià)了悠栓,食鹽的進(jìn)貨又很麻煩,索性都不再銷售食鹽了按价。這樣一來惭适,村里只有一個(gè)食鹽銷售的渠道,那就是村委會(huì)楼镐,再也沒有了過去的種種煩惱癞志,村民們無比擁護(hù)。
對(duì)比一下前后兩種食鹽銷售途徑:
第一種:多家雜貨店同時(shí)銷售
這種方式的問題是:每家銷售的食鹽價(jià)格不統(tǒng)一框产,質(zhì)量不統(tǒng)一凄杯。
第二種:村委會(huì)統(tǒng)一銷售
這種方法的好處是:銷售的食鹽價(jià)格統(tǒng)一,質(zhì)量穩(wěn)定
兩相對(duì)比秉宿,可以看出戒突,針對(duì)食鹽銷售這個(gè)場(chǎng)景,統(tǒng)一銷售要好于多家零散銷售描睦。
三.模式總結(jié)
我們上面采用的統(tǒng)一銷售的方式其實(shí)已經(jīng)使用了單例模式的思想:全局中只有一個(gè)實(shí)例膊存,并提供一個(gè)全局的訪問點(diǎn)。
類圖
使用場(chǎng)景
系統(tǒng)只需要一個(gè)實(shí)例對(duì)象忱叭,如系統(tǒng)需要生產(chǎn)唯一的序列號(hào)隔崎,則序列號(hào)生成器最好由唯一對(duì)象統(tǒng)一生成。
優(yōu)點(diǎn)
(1)提供唯一可以訪問的實(shí)例對(duì)象韵丑,從而可以更好的控制用戶行為
(2)由于只有一個(gè)實(shí)例爵卒,可以減少系統(tǒng)開銷
缺點(diǎn)
由于單例類是某個(gè)具體的類,而不是接口撵彻,因此擴(kuò)展性不足
幾種實(shí)現(xiàn)方式
方法一:靜態(tài)初始化
public class Singleton {
// 初始化階段完成實(shí)例創(chuàng)建
private static Singleton instance = new Singleton();
// 將構(gòu)造方法聲明為私有钓株,保證類外部無法調(diào)用
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
方法二:延遲實(shí)例化
方法一中实牡,實(shí)現(xiàn)過程簡(jiǎn)單,而且能保證線程安全享幽,但是有一個(gè)缺點(diǎn):不管instance最終有沒有被用到铲掐,都已經(jīng)被實(shí)例化拾弃,有可能造成資源浪費(fèi)值桩。另一類方法是延遲實(shí)例化:
// 線程不安全的單例模式
public class Singleton {
private static Singleton instance;
// 將構(gòu)造方法聲明為私有,保證類外部無法調(diào)用
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
上面代碼是線程不安全的豪椿,在多線程環(huán)境下奔坟,有可能創(chuàng)建出多個(gè)Singleton實(shí)例。
如果考慮到線程安全搭盾,有幾種辦法:
// 線程安全的單例模式
public class Singleton {
private static Singleton instance;
// 將構(gòu)造方法聲明為私有咳秉,保證類外部無法調(diào)用
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
注意到我們對(duì)getInstance方法進(jìn)行了同步操作,保證同一時(shí)刻鸯隅,只能有一個(gè)線程進(jìn)入方法體澜建。但是由于同步操作會(huì)降低性能,實(shí)時(shí)上蝌以,一旦完成初始化后炕舵,就不需要再進(jìn)行同步了,實(shí)際上是另一種資源浪費(fèi)跟畅。
雙重檢查加鎖:
// 線程安全的單例模式
public class Singleton {
private volatile static Singleton instance;
// 將構(gòu)造方法聲明為私有咽筋,保證類外部無法調(diào)用
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) { // 如果確實(shí)沒有被實(shí)例化,才進(jìn)行實(shí)例化
instance = new Singleton();
}
}
}
return instance;
}
}
在這個(gè)實(shí)現(xiàn)中徊件,一旦完成實(shí)例化奸攻,就不會(huì)再進(jìn)入synchronized同步塊鳄哭,從而不會(huì)造成性能問題静稻。
參考資料
- 《Head First設(shè)計(jì)模式》
- Graphic Design Patterns
本文已遷移至我的博客:http://ipenge.com/52281.html