1.什么是設(shè)計(jì)模式
設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用的剩燥、多數(shù)人知曉的澳骤、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)反番。設(shè)計(jì)模式代表了最佳的實(shí)踐沙热,通常被有經(jīng)驗(yàn)的面向?qū)ο蟮能浖_發(fā)人員所采用叉钥。設(shè)計(jì)模式是軟件開發(fā)人員在軟件開發(fā)過程中面臨的一般問題的解決方案。這些解決方案是眾多軟件開發(fā)人員經(jīng)過相當(dāng)長的一段時(shí)間的試驗(yàn)和錯(cuò)誤總結(jié)出來的篙贸。
項(xiàng)目中合理的運(yùn)用設(shè)計(jì)模式可以完美的解決很多問題
2.設(shè)計(jì)模式的分類
- 創(chuàng)建型模式:提供了一種在創(chuàng)建對象的同時(shí)隱藏創(chuàng)建邏輯的方式投队,而不是使用新的運(yùn)算符直接實(shí)例化對象。這使得程序在判斷針對某個(gè)給定實(shí)例需要?jiǎng)?chuàng)建哪些對象時(shí)更加靈活爵川。
- 結(jié)構(gòu)型模式:這類設(shè)計(jì)模式關(guān)注類和對象的組合敷鸦,繼承的概念被用來組合接口以及定義組合對象獲得新功能的方式。
- 行為型模式:這類設(shè)計(jì)模式更關(guān)注對象之間的通信雁芙。
3.單例模式(Singleton Pattern)
目的:使得類的一個(gè)對象成為該類系統(tǒng)中的唯一實(shí)例
定義:一個(gè)類有且僅有一個(gè)實(shí)例轧膘,并且自行實(shí)例化向整個(gè)系統(tǒng)提供
優(yōu)點(diǎn):
- 在內(nèi)存中只有一個(gè)對象钞螟,節(jié)省內(nèi)存空間
- 避免頻繁的創(chuàng)建銷毀對象兔甘,提高性能
- 避免對共享資源的多重占用
缺點(diǎn):
- 擴(kuò)展比較困難
- 如果實(shí)例化后的對象長期不利用,系統(tǒng)將默認(rèn)為垃圾進(jìn)行回收鳞滨, 造成對象狀態(tài)丟失
4.適用場景
1洞焙、創(chuàng)建對象時(shí)占用資源過多,但同時(shí)又需要用到該類
2拯啦、對系統(tǒng)內(nèi)資源要求統(tǒng)一讀寫澡匪,如讀寫配置信息
3、當(dāng)多個(gè)實(shí)例存在可能引起程序邏輯錯(cuò)誤褒链,如號(hào)碼生成器
實(shí)現(xiàn)方式一:懶漢式(線程不安全)
懶漢式:在第一次使用時(shí)進(jìn)行實(shí)例化對象唁情。
/**
* 懶漢式:實(shí)例創(chuàng)建對象時(shí)并不直接初始化,直到第一次調(diào)用get方法時(shí)才完成初始化操作
*/
public class Singleton {
// 1.創(chuàng)建該類的私有靜態(tài)實(shí)例
private static Singleton instance;
// 2.創(chuàng)建類中私有構(gòu)造
private Singleton (){}
// 3.創(chuàng)建公有靜態(tài)方法返回靜態(tài)實(shí)例對象
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
這種實(shí)現(xiàn)方式不支持多線程甫匹,因?yàn)闆]有同步鎖甸鸟,多線程下不能正常工作。
實(shí)現(xiàn)方式二:懶漢式(線程安全)
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static synchronized Singleton getInstance(){
if (instance == null){
instance = new Singleton();
}
return instance;
}
}
可以在多線程環(huán)境下使用兵迅,但是效率太低抢韭。
優(yōu)點(diǎn):一個(gè)對象初始化一次,節(jié)省內(nèi)存恍箭。
缺點(diǎn):必須用synchronized來維持單例刻恭,沒效率。
實(shí)現(xiàn)方式三:餓漢式(線程安全)
/**
* 餓漢式:創(chuàng)建對象實(shí)例的時(shí)候直接初始化 空間換時(shí)間
*/
public class Singleton {
// 1.創(chuàng)建類中私有構(gòu)造
private Singleton(){
}
// 2.創(chuàng)建該類的私有靜態(tài)實(shí)例
private static Singleton instance = new Singleton();
// 3.創(chuàng)建公有靜態(tài)方法返回靜態(tài)實(shí)例對象
public static Singleton getInstance(){
return instance;
}
}
因?yàn)樗鳛殪o態(tài)資源扯夭,所以在類裝載時(shí)就被實(shí)例化
優(yōu)點(diǎn):沒有加鎖鳍贾,執(zhí)行效率會(huì)提高。
缺點(diǎn):類加載時(shí)就初始化交洗,浪費(fèi)內(nèi)存骑科。
實(shí)現(xiàn)方式四:雙檢鎖/雙重校驗(yàn)鎖DCL(線程安全)
public class Singleton {
private Singleton(){
}
private static Singleton instance;
public static Singleton getInstance(){
if (instance == null){
// 將鎖的范圍縮小,提高性能
synchronized (Singleton.class){
// 再判斷一次是否為null
if (instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
采用雙鎖機(jī)制藕筋,安全且在多線程情況下能保持高性能纵散。詳細(xì)了解請點(diǎn)擊:Java并發(fā)編程 -- 單例模式線程安全問題
實(shí)現(xiàn)方式五:登記式/靜態(tài)內(nèi)部類(線程安全)
public class Singleton {
private Singleton(){
}
// 使用內(nèi)部類的方式來實(shí)現(xiàn)懶加載
private static class SingletonHandler{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHandler.INSTANCE;
}
}
這種方式可以說是惡漢式的變通版梳码,SingletonHandler沒有被主動(dòng)使用的情況下是不會(huì)實(shí)例化Singleton對象的,所以這樣做伍掀,既能達(dá)到lazy式的加載掰茶,又能保證線程安全。
實(shí)現(xiàn)方式六:枚舉類(線程安全)
public enum Singleton {
INSTANCE;
public void myMethod() {
System.out.println("enum instance test");
}
}
它不僅能避免多線程同步問題蜜笤,而且還自動(dòng)支持序列化機(jī)制濒蒋,防止反序列化重新創(chuàng)建新的對象,絕對防止多次實(shí)例化把兔。
測試:
public class Main {
public static void main(String[] args) {
Singleton singleton = Singleton.INSTANCE;
singleton.myMethod();
}
}
enum instance test
總結(jié)
不建議使用第 1 種和第 2 種懶漢方式沪伙,建議使用第 3 種餓漢方式。只有在要明確實(shí)現(xiàn) lazy loading 效果時(shí)县好,才會(huì)使用第 5 種登記方式围橡。如果涉及到反序列化創(chuàng)建對象時(shí),可以嘗試使用第 6 種枚舉方式缕贡。