簡介
姓名:單例模式
英文名:singleton pattern
價值觀:我的生活我主宰(只允許自己例項化,不願意被其他物件例項化)
個人介紹:
ensure a class has only one instance, and provide a global point of access to it.(確保某乙個類只有乙個例項,而且自行例項化並向整個系統提供這個例項。)
(來自《設計模式之禪》)
這裡的關注點有 3 個,分別是:
1. 只有乙個例項
2. 自行例項化(也就是主動例項化)
3. 向整個系統提供這個例項
你要的故事
我們腦洞大開來用乙個故事講解一番。
小明家裡有一輛小汽車,具體什麼牌子就不知道了,咱也不關注,反正他家裡就這麼一輛車,小明比較懶,只要一出門都會開車,例如去旅遊、去學校、去聚會都會開車去。下面模擬小明出去的場景。
class car
}class xiaoming
public car gotoschool()
public car gettogether()
}public class singletonerrortest
}
上面小汽車只有乙個方法,就是走。小明去旅遊、去學校、參加聚會都開著他唯一的一輛汽車車去。是不是有人有疑問?為什麼每個方法都返回 car 物件?其實只是想在下面做一次檢查,檢查小明去旅遊、去學校和參加聚會的車是不是同一輛。下面是檢查**:
system.out.println("car1 == car2 ? " + (car1 == car2));
system.out.println("car2 == car3 ? " + (car2 == car3));
最終結果是啥?很明顯是 2 個 false。小明去旅遊、去學校和參加聚會的車都不相同,小明不是只有 1 輛車?關鍵在於 car car = new car(); 這一句**,其實這一句是建立一輛車,每次都重新建立一輛。那應該怎麼實現小明只有一輛車呢?這時候就引入了單例模式。
上面我們說到了單例模式需要具備的 3 個點:只有 1 個例項,很顯然,上面的**不止 1 個例項,而是有 3 個 car 例項;自行例項化,car 本身沒有主動例項化,而是在小明需要用到的時候才例項化;向整個系統提供這個例項,因為 car 沒有主動例項化,所以它沒法向外部暴露提供自己出來。
我們的**完全不符合單例模式的要求。我們要通過修改,使之符合單例模式的 3 個要點。首先需要實現的是第 2 點,把 car 例項化從小明轉為 car 本身,如下**:
class car1
public void run()
}
上面**使用 private 修飾構造方法,使得 car1 不能被其他使用方例項化,通過 car1 car1 = new car1(); 主動例項化自己。
接下來再實現第 3 點,向整個系統暴露這個例項,也就是暴露它自己。每個使用方都呼叫 car1.getinstance() 方法來獲取例項。
class car1
private car1()
public void run()
}
上面**就實現了單例模式的 2 和 3 要點,第 1 要點要怎麼實現呢?告訴你,不用實現,只要滿足了 2 和 3 要點就可以,第 1 要點是用來檢驗是否是單例模式的好思路。我們檢驗一下
class car1
private car1()
public void run()
}class xiaoming1
public car1 gotoschool()
public car1 gettogether()
}public class singletonrighthungrytest
}
上面**最後兩行列印出來的結果是啥?是我們想要的:2 個 true。說明小明這幾次外出開的車都是同一輛。這是最簡單的單例模式的實現方式,我們經常稱作餓漢式單例模式。為什麼起這麼古怪的名字呢?其實和對應的懶漢式單例模式有關,這是 2 個實現方式的差別,餓漢式單例模式實現方式在類載入到記憶體的時候,就建立好物件了,而懶漢式則是在第一次使用的時候才建立物件,也就是把建立物件的時機從載入延遲到第一次使用,所以才有懶餓之分。
下面我們來看怎麼實現懶漢式單例模式。先描述一下場景:小明還沒有汽車,他也不知道什麼時候要買汽車,突然某一天,他想去旅遊,覺得是時候買輛車了,然後他就買車去旅遊了,旅遊回來又開車去學校和參加聚會。
class car2
return car2;
}private car2()
public void run()
}class xiaoming2
public car2 gotoschool()
public car2 gettogether()
}public class singletonrightlazytest
}小明去旅遊
買車啦。。。
走。。。。
小明去學校
走。。。。
小明參加聚會
走。。。。
car1 == car2 ? true
car2 == car3 ? true
上面附帶了列印出來的結果,小明要去旅遊的時候,才去買車。這就是懶漢式單例模式的實現方式。
要注意懶漢式單例模式有個很關鍵的一點就是 getinstance() 方法帶上了 synchronized,這個是為什麼呢?
首先得了解關鍵字 synchronized 的作用是什麼:用於修飾執行方法同步,也就是說多執行緒併發的情況下,在乙個時間點,只允許乙個執行緒執行這個方法。
不加上這個會有什麼結果?在多執行緒併發情況下,如果有 2 個執行緒同時執行到 if(null == car2),那麼都判斷為 true,這時 2 個執行緒都會執行 car2 = new car2(),這樣子就不是單例了。
總結
單例模式可以說是設計模式中最簡單的乙個,也是在工作中很多場景下經常用到的,比如:專案的配置檔案載入、各種工具類等等。我們對於單例模式最重要的一點就是要考慮多執行緒併發,沒有考慮這點就容易引發單例物件不單例的情況。而單例給我們帶來最大的好處就是節約記憶體。
上面實現的兩種方法是單例模式中最最最簡單的 2 種實現,相信也是用得最多的實現方式。網上有不少網友分享了單例模式的很多種實現方法,大家也可以去了解,在了解之前務必已經搞懂文中這 2 種最簡單的實現方式,不然會頭暈的。
建立型模式 單例模式
餓漢式 package com.hfview.designmode.signle 1.餓漢式 就是在初始化成員變數的時候就獲取例項物件 2.public class signlemode private signlemode 懶漢式 package com.hfview.designmode.sig...
建立型模式 單例模式
概述 保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。適用性 當類只能有乙個事例而且客戶可以從乙個眾所周知的訪問點訪問它時。當這個唯一事例應該是通過子類化可擴充套件的,並且客戶應該無需更改 就能使用乙個擴充套件的例項時。參與者 singleton 定義乙個instance操作,允許客戶訪問它...
建立型模式 單例模式
1.乙個類只能建立乙個物件 2.應用 主要應用與資料庫應用,可以避免大量的new操作消耗資源 3.uml類圖 user 何曉巨集 date 2018 9 27 time 15 48 namespace singleton class singleton 判斷 instance是否為空,為空則新建乙個...