文章首發(fā):
創(chuàng)建型模式:?jiǎn)卫J?/p>
上面小汽車只有一個(gè)方法,就是走。小明去旅游、去學(xué)校、參加聚會(huì)都開(kāi)著他唯一的一輛汽車車去。是不是有人有疑問(wèn)?為什么每個(gè)方法都返回 Car 對(duì)象?其實(shí)只是想在下面做一次檢查,檢查小明去旅游、去學(xué)校和參加聚會(huì)的車是不是同一輛。下面是檢查代碼:
System.out.println("car1 == car2 ? " + (car1 == car2));
System.out.println("car2 == car3 ? " + (car2 == car3));
最終結(jié)果是啥?很明顯是 2 個(gè) false。小明去旅游、去學(xué)校和參加聚會(huì)的車都不相同,小明不是只有 1 輛車?關(guān)鍵在于 Car car = new Car();
這一句代碼,其實(shí)這一句是創(chuàng)建一輛車,每次都重新創(chuàng)建一輛。那應(yīng)該怎么實(shí)現(xiàn)小明只有一輛車呢?這時(shí)候就引入了單例模式。
上面我們說(shuō)到了單例模式需要具備的 3 個(gè)點(diǎn):只有 1 個(gè)實(shí)例,很顯然,上面的代碼不止 1 個(gè)實(shí)例,而是有 3 個(gè) Car 實(shí)例;自行實(shí)例化,Car 本身沒(méi)有主動(dòng)實(shí)例化,而是在小明需要用到的時(shí)候才實(shí)例化;向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,因?yàn)?Car 沒(méi)有主動(dòng)實(shí)例化,所以它沒(méi)法向外部暴露提供自己出來(lái)。
我們的代碼完全不符合單例模式的要求。我們要通過(guò)修改,使之符合單例模式的 3 個(gè)要點(diǎn)。首先需要實(shí)現(xiàn)的是第 2 點(diǎn),把 Car 實(shí)例化從小明轉(zhuǎn)為 Car 本身,如下代碼
class Car1{
private static Car1 car1 = new Car1();
private Car1() {
}
public void run(){
System.out.println("走。。。。");
}
}
上面代碼使用 private 修飾構(gòu)造方法,使得 Car1 不能被其他使用方實(shí)例化,通過(guò) Car1 car1 = new Car1();
主動(dòng)實(shí)例化自己。
接下來(lái)再實(shí)現(xiàn)第 3 點(diǎn),向整個(gè)系統(tǒng)暴露這個(gè)實(shí)例,也就是暴露它自己。每個(gè)使用方都調(diào)用 Car1.getInstance()
方法來(lái)獲取實(shí)例。
class Car1{
private static Car1 car1 = new Car1();
public static Car1 getInstance() {
return car1;
}
private Car1() {
}
public void run(){
System.out.println("走。。。。");
}
}
上面代碼就實(shí)現(xiàn)了單例模式的 2 和 3 要點(diǎn),第 1 要點(diǎn)要怎么實(shí)現(xiàn)呢?告訴你,不用實(shí)現(xiàn),只要滿足了 2 和 3 要點(diǎn)就可以,第 1 要點(diǎn)是用來(lái)檢驗(yàn)是否是單例模式的好思路。我們檢驗(yàn)一下
class Car1{
private static Car1 car1 = new Car1();
public static Car1 getInstance() {
return car1;
}
private Car1() {
}
public void run(){
System.out.println("走。。。。");
}
}
class XiaoMing1 {
public Car1 travel() {
System.out.println("小明去旅游");
Car1 car = Car1.getInstance();
car.run();
return car;
}
public Car1 goToSchool() {
System.out.println("小明去學(xué)校");
Car1 car = Car1.getInstance();
car.run();
return car;
}
public Car1 getTogether() {
System.out.println("小明參加聚會(huì)");
Car1 car = Car1.getInstance();
car.run();
return car;
}
}
public class SingletonRightHungryTest {
public static void main(String[] args) {
XiaoMing1 xiaoMing1 = new XiaoMing1();
Car1 car1 = xiaoMing1.travel();
Car1 car2 = xiaoMing1.goToSchool();
Car1 car3 = xiaoMing1.getTogether();
System.out.println("car1 == car2 ? " + (car1 == car2));
System.out.println("car2 == car3 ? " + (car2 == car3));
}
}
上面代碼最后兩行打印出來(lái)的結(jié)果是啥?是我們想要的:2 個(gè) true。說(shuō)明小明這幾次外出開(kāi)的車都是同一輛。這是最簡(jiǎn)單的單例模式的實(shí)現(xiàn)方式,我們經(jīng)常稱作餓漢式單例模式。為什么起這么古怪的名字呢?其實(shí)和對(duì)應(yīng)的懶漢式單例模式有關(guān),這是 2 個(gè)實(shí)現(xiàn)方式的差別,餓漢式單例模式實(shí)現(xiàn)方式在類加載到內(nèi)存的時(shí)候,就創(chuàng)建好對(duì)象了,而懶漢式則是在第一次使用的時(shí)候才創(chuàng)建對(duì)象,也就是把創(chuàng)建對(duì)象的時(shí)機(jī)從加載延遲到第一次使用,所以才有懶餓之分。
下面我們來(lái)看怎么實(shí)現(xiàn)懶漢式單例模式。先描述一下場(chǎng)景:小明還沒(méi)有汽車,他也不知道什么時(shí)候要買汽車,突然某一天,他想去旅游,覺(jué)得是時(shí)候買輛車了,然后他就買車去旅游了,旅游回來(lái)又開(kāi)車去學(xué)校和參加聚會(huì)。
class Car2{
private static Car2 car2;
public static synchronized Car2 getInstance() {
if (null == car2) {
System.out.println("買車?yán)?。?!?);
car2 = new Car2();
}
return car2;
}
private Car2() {
}
public void run(){
System.out.println("走。。。。");
}
}
class XiaoMing2
{
public Car2 travel() {
System.out.println("小明去旅游");
Car2 car = Car2.getInstance();
car.run();
return car;
}
public Car2 goToSchool() {
System.out.println("小明去學(xué)校");
Car2 car = Car2.getInstance();
car.run();
return car;
}
public Car2 getTogether() {
System.out.println("小明參加聚會(huì)");
Car2 car = Car2.getInstance();
car.run();
return car;
}
}
public class SingletonRightLazyTest {
public static void main(String[] args) {
XiaoMing2 xiaoMing2 = new XiaoMing2();
Car2 car1 = xiaoMing2.travel();
Car2 car2 = xiaoMing2.goToSchool();
Car2 car3 = xiaoMing2.getTogether();
System.out.println("car1 == car2 ? " + (car1 == car2));
System.out.println("car2 == car3 ? " + (car2 == car3));
}
}
小明去旅游
買車?yán)病??!?走。。。。
小明去學(xué)校
走。。。。
小明參加聚會(huì)
走。。。。
car1 == car2 ? true
car2 == car3 ? true
上面附帶了打印出來(lái)的結(jié)果,小明要去旅游的時(shí)候,才去買車。這就是懶漢式單例模式的實(shí)現(xiàn)方式。
要注意懶漢式單例模式有個(gè)很關(guān)鍵的一點(diǎn)就是 getInstance() 方法帶上了 synchronized,這個(gè)是為什么呢?
首先得了解關(guān)鍵字 synchronized 的作用是什么:用于修飾執(zhí)行方法同步,也就是說(shuō)多線程并發(fā)的情況下,在一個(gè)時(shí)間點(diǎn),只允許一個(gè)線程執(zhí)行這個(gè)方法。
不加上這個(gè)會(huì)有什么結(jié)果?在多線程并發(fā)情況下,如果有 2 個(gè)線程同時(shí)執(zhí)行到 if(null == car2),那么都判斷為 true,這時(shí) 2 個(gè)線程都會(huì)執(zhí)行 car2 = new Car2(),這樣子就不是單例了。
單例模式可以說(shuō)是設(shè)計(jì)模式中最簡(jiǎn)單的一個(gè),也是在工作中很多場(chǎng)景下經(jīng)常用到的,比如:項(xiàng)目的配置文件加載、各種工具類等等。我們對(duì)于單例模式最重要的一點(diǎn)就是要考慮多線程并發(fā),沒(méi)有考慮這點(diǎn)就容易引發(fā)單例對(duì)象不單例的情況。而單例給我們帶來(lái)大的好處就是節(jié)約內(nèi)存。
上面實(shí)現(xiàn)的兩種方法是單例模式中最最最簡(jiǎn)單的 2 種實(shí)現(xiàn),相信也是用得最多的實(shí)現(xiàn)方式。網(wǎng)上有不少網(wǎng)友分享了單例模式的很多種實(shí)現(xiàn)方法,大家也可以去了解,在了解之前務(wù)必已經(jīng)搞懂文中這 2 種最簡(jiǎn)單的實(shí)現(xiàn)方式,不然會(huì)頭暈的。
希望文章對(duì)您有所幫助,設(shè)計(jì)模式系列會(huì)持續(xù)更新,感興趣的同學(xué)可以關(guān)注公眾號(hào)LieBrother,第一時(shí)間獲取文章推送閱讀,也可以一起交流,交個(gè)朋友。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場(chǎng)景需求。
網(wǎng)站名稱:創(chuàng)建型模式:?jiǎn)卫J?創(chuàng)新互聯(lián)
網(wǎng)站地址:http://chinadenli.net/article48/ddedhp.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、網(wǎng)站策劃、網(wǎng)站制作、網(wǎng)站導(dǎo)航、靜態(tài)網(wǎng)站、域名注冊(cè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容