常見設(shè)計(jì)模式總結(jié)

分類


設(shè)計(jì)模式共分為三種類型:創(chuàng)建型辆布、結(jié)構(gòu)型檬贰、行為型

  • 創(chuàng)建型:用于創(chuàng)建對象庐扫,為設(shè)計(jì)類實(shí)例化新對象提供指南
  • 結(jié)構(gòu)型:用于處理類或?qū)ο蟮慕M合瞳脓,對類如何設(shè)計(jì)以形成更大的結(jié)構(gòu)提供指南
  • 行為型:用于描述類或?qū)ο蟮慕换ヒ约奥氊?zé)的分配塑娇,對類之間交互以及分配職責(zé)的方式提供指南

定義來自權(quán)威的軟考

常見的設(shè)計(jì)模式有如下幾種

創(chuàng)建型:構(gòu)建者、單例劫侧、工廠
結(jié)構(gòu)型:適配器钝吮、代理、外觀
行為型:策略板辽、觀察者、責(zé)任鏈

正文


Builder構(gòu)建者

  • 場景
    用于生成對象的類其內(nèi)部結(jié)構(gòu)過于復(fù)雜棘催,為屏蔽類的復(fù)雜性劲弦,需要將類的構(gòu)建和表示進(jìn)行分離,用最少的參數(shù)生成對象

  • 例子


    OkHttpClient

產(chǎn)生實(shí)際對象的必需參數(shù)是從builder對象中取出的

即使什么參數(shù)也不傳Builder也會生成默認(rèn)參數(shù)醇坝,以支持對象的生成

Builder

每次添加參數(shù)時邑跪,記得返回Builder對象次坡,用以鏈?zhǔn)降膫鬟f

這是OkHttpClient對象傳遞參數(shù)的精妙之處,源碼內(nèi)多處使用

Singleton單例

  • 場景
    保證實(shí)例是唯一的存在画畅,以保證操作的唯一性

單例模式的實(shí)現(xiàn)有兩種:飽漢砸琅、餓漢模式
聯(lián)想記憶:飽漢不餓,需要的時候再吃轴踱;餓漢很饑症脂,提前搶著吃
飽漢其實(shí)是懶加載,不必提前占內(nèi)存

  • 例子
//飽漢模式
public class SingletonClass{
    private static volatile SingletonClass instance=null;//靜態(tài)變量保證對象的唯一性淫僻,volatile關(guān)鍵字防止指令重排

    public static SingletonClass getInstance(){//使用內(nèi)部加鎖诱篷,避免每次調(diào)用時無謂的加鎖,提升了性能
        if(instance==null){//指令重排的話雳灵,其他線程看到instance不空棕所,則不會進(jìn)入,也不會加鎖悯辙,直接返回半成品instance琳省,從而導(dǎo)致異常
            synchronized(SingletonClass.class){//鎖對象最好是類對象(個人觀點(diǎn))
                if(instance==null)//再判斷一遍,避免多個線程在上一行同時被鎖住躲撰,釋放后進(jìn)入针贬,再次實(shí)例化對象
                    instance=new SingletonClass();//指令重排發(fā)生地
            }
        }
        return instance;
    }

    private SingletonClass(){//私有構(gòu)造方法,防止實(shí)例化
    }
}
//餓漢模式
public static class Singleton{//靜態(tài)類直接進(jìn)入方法區(qū)常量池

    private static final Singleton instance = new Singleton();//靜態(tài)常量進(jìn)入方法區(qū)常量池

    private Singleton(){//私有構(gòu)造方法茴肥,防止實(shí)例化
    }

    public static Singleton getInstance(){//靜態(tài)方法
        return instance;
    }
}

餓漢模式坚踩,由于事先分配內(nèi)存空間不存在飽漢的多線程問題,但其常駐內(nèi)存會造成開銷問題瓤狐,不同的場景需采用不同的手段以保證消耗與效率的平衡瞬铸。

Factory工廠

  • 場景
    多態(tài)場景下,用以管理生成不同的對象础锐,并且耦合度不能夠過高

  • 例子

簡單工廠模式

public interface Phone {//Phone是產(chǎn)品抽象
}

public class Honor implements Phone{//Honor是具體的產(chǎn)品
}

public class Mate20 implements Phone{//Mate20是具體的產(chǎn)品
}

public class HuaWei {//具體的廠商

    public static Phone create(String str){//廠商根據(jù)要求生產(chǎn)手機(jī)
        
        if(str.equalsIgnoreCase("honor")){
            return new Honor();
        }
        else if(str.equalsIgnoreCase("mate20")){
            return new Mate20();
        }
        return null;
    }

}

工廠方法模式

public interface Phone {//Phone是產(chǎn)品抽象
}

public interface Factory {//Factory是廠商抽象
    public Phone create();
}

public class HWPhone implements Phone{//華為手機(jī)
}

public class MPhone implements Phone{//小米手機(jī)
}

public class HuaWei implements Factory {//華為產(chǎn)華為手機(jī)
    public Phone create(){
        return new HWPhone();
    }
}

public class XiaoMi implements Factory {//小米產(chǎn)小米手機(jī)
    public Phone create(){
        return new MPhone();
    }
}

簡單工廠模式:一個工廠類嗓节,工廠生產(chǎn)各種產(chǎn)品

工廠方法模式:一個工廠接口,多個工廠類皆警,不同工廠生產(chǎn)不同產(chǎn)品

工廠方法模式的改進(jìn)在于拦宣,減輕了簡單工廠模式中工廠類的復(fù)雜度,具體的產(chǎn)出交由具體的工廠類信姓,降低了耦合度鸵隧。

抽象工廠模式

public interface Phone {//Phone是產(chǎn)品抽象
}

public interface OS {//OS是產(chǎn)品抽象
}

public interface Factory {//Factory是廠商抽象
    public Phone create();

    public OS develop();
}

public class HWPhone implements Phone{//華為手機(jī)
}

public class MPhone implements Phone{//小米手機(jī)
}

public class MIUI implements OS{//系統(tǒng)
}

public class EMUI implements OS{//系統(tǒng)
}

public class HuaWei implements Factory{//華為產(chǎn)華為手機(jī)
    public Phone create(){
        return new HWPhone();
    }

    public OS develop(){
        return new EMUI();
    }
}

public class XiaoMi implements Factory{//小米產(chǎn)小米手機(jī)
    public Phone create(){
        return new MPhone();
    }
    public OS develop(){
        return new MIUI();
    }
}

抽象工廠模式較工廠方法模式的區(qū)別在于,不生產(chǎn)單一產(chǎn)品意推,使工廠能夠生產(chǎn)不同類型的相關(guān)產(chǎn)品豆瘫,從而提高擴(kuò)展性

在Retrofit中

使用的是工廠方法模式,將工廠抽象

初始化階段菊值,將實(shí)例化的不同工廠放在List中外驱,根據(jù)參數(shù)使用情景的不同育灸,再在List中取出合適的工廠進(jìn)行處理。

Adapter適配器

  • 場景
    已有類的功能不滿足需求昵宇,需將功能進(jìn)行轉(zhuǎn)換磅崭,以達(dá)到匹配

  • 例子

類適配器模式

原有類并不具備某功能,通過創(chuàng)建Adapter類瓦哎,繼承原有功能砸喻、實(shí)現(xiàn)目標(biāo)功能接口,從滿足功能要求

public class Source {//現(xiàn)有類
    public void method1() {  
        System.out.println("this is original method!");  
    }  
}  

public interface Targetable {//目標(biāo)功能
  
    public void method1();  
  
    public void method2();//缺失功能
}  

public class Adapter extends Source implements Targetable {  
  
    @Override  
    public void method2() {//補(bǔ)足缺失
        System.out.println("this is the targetable method!");  
    }  
} 

對象適配器模式

不同于類適配器模式杭煎,通過繼承恩够、實(shí)現(xiàn)這種高耦合手段,以滿足功能要求羡铲。對象適配器模式采用的是聚合的手段蜂桶,創(chuàng)建新類Wrapper通過持有原類對象具備原有功能外;并且類Wrapper實(shí)現(xiàn)功能接口補(bǔ)足缺失功能

如OkHttpClient中的Cache類

在OkHttpClient中緩存攔截器一層使用的是InternalCache也切,見注釋扑媚,官方已經(jīng)不建議使用此類改用Cache

Cache類本身并沒有實(shí)現(xiàn)InternalCache接口,而是持有一個InternalCache對象雷恃,且對象內(nèi)的方法都是調(diào)用Cache內(nèi)的

接口適配器模式

不同于類適配器模式疆股、對象適配器模式的補(bǔ)足功能,接口適配器模式恰恰相反:不暴露功能倒槐。

當(dāng)接口方法過多旬痹,而我們關(guān)心的卻寥寥可數(shù)時,通過實(shí)現(xiàn)接口的方式就會空實(shí)現(xiàn)很多不必要的方法讨越。通過两残,創(chuàng)建新類(或抽象類)空實(shí)現(xiàn)所有方法,實(shí)際使用時繼承自新類重寫關(guān)心的方法把跨,就避免了每次實(shí)現(xiàn)方法過多的問題人弓,這種設(shè)計(jì)的原則是接口隔離,對接口知道的越少越好

如OkHttp中的回調(diào)監(jiān)聽EventListener

所有階段的回調(diào)都空實(shí)現(xiàn)着逐,當(dāng)我關(guān)心某一階段的回調(diào)時崔赌,就重寫對應(yīng)方法,否則20個回調(diào)方法每添加一次監(jiān)聽就都要實(shí)現(xiàn)一遍耸别,代碼的易讀性也不好

Proxy代理

代理分靜態(tài)代理和動態(tài)代理健芭,這里列舉的是靜態(tài)代理

  • 場景
    原有類的功能需要進(jìn)行擴(kuò)充

  • 例子

public interface Sourceable {  
    public void method();  
} 

public class Source implements Sourceable {//原類
  
    @Override  
    public void method() {  
        System.out.println("the original method!");  
    }  
}  

public class Proxy implements Sourceable {//代理類
  
    private Source source;  
    public Proxy(){  
        super();  
        this.source = new Source();  
    }  
    @Override  
    public void method() {  
        before();  
        source.method();  
        atfer();  
    }  
    private void atfer() {  
        System.out.println("after proxy!");  
    }  
    private void before() {  
        System.out.println("before proxy!");  
    }  
}  

原類與代理類都實(shí)現(xiàn)了相同的接口,方法的實(shí)際執(zhí)行是由代理對象觸發(fā)的秀姐,只不過代理對象在方法觸發(fā)前后增加了其他功能吟榴。

有點(diǎn)和對象適配器模式類似都實(shí)現(xiàn)相關(guān)接口、持有原類對象囊扳,但

  • 對象適配器模式是為了彌補(bǔ)功能上的不足
  • 代理模式是給功能進(jìn)行加強(qiáng)

一個是彌補(bǔ)功能吩翻,一個是加強(qiáng)功能這是兩種模式的區(qū)別

從上來看對象適配器模式中的Cache例子放錯位置了,它應(yīng)該屬于靜態(tài)代理模式锥咸,Cache是被代理類狭瞎,InternalCache是代理類

Facade外觀

  • 場景
    多個類間有依賴關(guān)系時,由多個類組合創(chuàng)建新類

  • 例子

OkHttpClient和Retrofit類就是明顯的外觀模式搏予,其內(nèi)部由多個功能不同的類對象組成熊锭,外部的單一操作實(shí)際影響內(nèi)部多個對象間的聯(lián)動。

Strategy策略

  • 場景
    相同的方法雪侥,根據(jù)不同的情景有不同的實(shí)現(xiàn)

  • 例子
    以前做過比特幣的自動交易軟件碗殷,實(shí)際操作就兩種:買、賣速缨,但是針對不同的行情锌妻、手上的持倉和現(xiàn)金情況,買和賣就變得有學(xué)問了:
    行情好的時候采用激進(jìn)策略旬牲,大膽買賣仿粹;
    行情差的時候就要高拋低吸,慢慢來原茅;

Observer觀察者

  • 場景
    某一對象狀態(tài)發(fā)生變化時吭历,其他對象需要及時的告知

  • 例子
    android中的回調(diào)就是觀察者模式,簡單點(diǎn)的:給一個button設(shè)置onClickListener擂橘,此時觀察者就是onClickListener被觀察者是button晌区,setOnClickListener是給兩者創(chuàng)建關(guān)聯(lián),當(dāng)被觀察者button被單擊通贞,觀察者onClickListener就會作出回應(yīng)朗若。

Chain of Responsibility責(zé)任鏈

  • 場景
    問題一次得不到解決,需要層層處理并傳遞滑频,每次將任務(wù)細(xì)化

  • 例子
    最有名的當(dāng)數(shù)OkHttp捡偏,其中的鏈?zhǔn)黔h(huán)形鏈


有些自己用的比較熟的或沒太多重點(diǎn)要記錄的就沒有貼例子,一般這種模式比較常見且簡單

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末峡迷,一起剝皮案震驚了整個濱河市银伟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绘搞,老刑警劉巖彤避,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異夯辖,居然都是意外死亡琉预,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門蒿褂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來圆米,“玉大人卒暂,你說我怎么就攤上這事÷μ” “怎么了也祠?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長近速。 經(jīng)常有香客問我诈嘿,道長,這世上最難降的妖魔是什么削葱? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任奖亚,我火速辦了婚禮,結(jié)果婚禮上析砸,老公的妹妹穿的比我還像新娘昔字。我一直安慰自己,他們只是感情好干厚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布李滴。 她就那樣靜靜地躺著,像睡著了一般蛮瞄。 火紅的嫁衣襯著肌膚如雪所坯。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天挂捅,我揣著相機(jī)與錄音芹助,去河邊找鬼。 笑死闲先,一個胖子當(dāng)著我的面吹牛状土,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播伺糠,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蒙谓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了训桶?” 一聲冷哼從身側(cè)響起累驮,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舵揭,沒想到半個月后谤专,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡午绳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年置侍,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡蜡坊,死狀恐怖杠输,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情秕衙,我是刑警寧澤抬伺,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站灾梦,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏妓笙。R本人自食惡果不足惜若河,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望寞宫。 院中可真熱鬧萧福,春花似錦、人聲如沸辈赋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钥屈。三九已至悟民,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間篷就,已是汗流浹背射亏。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留竭业,地道東北人智润。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像未辆,于是被迫代替她去往敵國和親窟绷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計(jì)模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計(jì)原則時需要注意以下幾點(diǎn):a) 高內(nèi)聚咐柜、低耦合和單一職能的“沖突”實(shí)際上兼蜈,這兩者...
    彥幀閱讀 3,746評論 0 14
  • 今天我們來總結(jié)下我們所學(xué)習(xí)的設(shè)計(jì)模式 面向?qū)ο蟮牧笤瓌t Android 設(shè)計(jì)模式之面向?qū)ο蟮牧笤瓌t 面向?qū)ο蟮?..
    AntDream閱讀 1,950評論 0 37
  • 設(shè)計(jì)模式匯總 一、基礎(chǔ)知識 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用炕桨、多...
    MinoyJet閱讀 3,947評論 1 15
  • 這個GIS+大數(shù)據(jù)的時代 沒有誰會精準(zhǔn)定位到一條豬 不對饭尝,是兩條 一條靠著一棵倒下的樹 從新葉走向奄息的樹根 一條...
    月光在上閱讀 150評論 0 1
  • 引言 最近有朋友問我,類似于新浪微博的tabBar中間有個加號是怎么去做的献宫,然后夏夏就說可以自己寫個UIView取...
    __夏至未至閱讀 2,266評論 3 7