(Boolan)C++設(shè)計(jì)模式 <八> ——門面模式(Facade)、代理模式(Proxy)榄棵、適配器(Adapter)以及中介者(Mediator)

“接口隔離”模式

在組建構(gòu)建過程中凝颇,某些接口之間直接的依賴常常會(huì)帶來很多問題、甚至根本無法實(shí)現(xiàn)疹鳄。采用添加一層間接接口(穩(wěn)定的)拧略,來隔離本來相互緊密關(guān)聯(lián)的接口是一種常見的解決方案

  • 典型模式
    1. Facade
    • Proxy
    • Adapter
    • Mediator

門面模式(Facade)

  • 系統(tǒng)間的耦合的復(fù)雜度
系統(tǒng)間耦合的復(fù)雜度

對(duì)于客戶系統(tǒng)和子系統(tǒng)之前存在很多的耦合的情況,如果不考慮設(shè)計(jì)的情況瘪弓,那么會(huì)形成A方案的情況垫蛆,系統(tǒng)的依賴嚴(yán)重,維護(hù)性大大降低腺怯。

如果在客戶層和子系統(tǒng)之間添加一層Facade袱饭,那么客戶系統(tǒng)之和Facade打交道,子系統(tǒng)中也只和Facade打交道呛占,那么在這時(shí)候虑乖,也就減少了客戶和自系統(tǒng)的依賴程度,相對(duì)使兩個(gè)系統(tǒng)更加獨(dú)立晾虑,可維護(hù)提高疹味。

  • 動(dòng)機(jī)
    上述方案A的問題在于組件的客戶和組件中的各種復(fù)雜的子系統(tǒng)有了過多的耦合仅叫,隨著外部客戶程序和子系統(tǒng)的演化,這種過多的耦合面臨很多變化的挑戰(zhàn)佛猛。

為子系統(tǒng)中的一組接口提供一個(gè)一致(穩(wěn)定)的界面惑芭,F(xiàn)acade模式定義了一個(gè)高層接口,這個(gè)接口使得這一子系統(tǒng)更加容易使用(復(fù)用)继找。
——《設(shè)計(jì)模式》GoF

  • Facade的結(jié)構(gòu)

對(duì)于Facade來說其實(shí)沒有固定的結(jié)構(gòu)可循遂跟,很多時(shí)候看起來代碼差別很大情況,但都是Facade模式婴渡。

而Facade更多的表達(dá)是一種設(shè)計(jì)原則和思想幻锁。
比如數(shù)據(jù)庫(kù)的訪問層(持久層的接口)就是一種典型的Facade模式。

  • 要點(diǎn)總結(jié)
    從客戶程序角度來看边臼,F(xiàn)acade模式簡(jiǎn)化了整個(gè)組建系統(tǒng)的接口哄尔,對(duì)于組建內(nèi)部與外部客戶程序來說,達(dá)到了一種“解耦”的效果——內(nèi)部子系統(tǒng)的任何變化不會(huì)影響到Facade接口的變化柠并。
    Facade設(shè)計(jì)模式更注重從構(gòu)架的層次去看整個(gè)系統(tǒng)岭接,而不是單個(gè)類的層次,F(xiàn)acade很多時(shí)候更是一種架構(gòu)設(shè)計(jì)的模式
    Facade設(shè)計(jì)模式并非一個(gè)集裝箱臼予,可以任意的放入任何多個(gè)對(duì)象鸣戴。Facade模式中組件的內(nèi)部應(yīng)該是“相互耦合關(guān)系比較大的一系列組件”,而不是簡(jiǎn)單的功能集合粘拾,以便能夠?qū)崿F(xiàn)松耦合窄锅,高內(nèi)聚的特性。

代理模式(Proxy)

  • 動(dòng)機(jī)
    在面向?qū)ο笙到y(tǒng)中缰雇,有些對(duì)象由于某種原因(比如對(duì)象創(chuàng)建開銷很大或者某些操作需要安全控制或者需要進(jìn)程外訪問等)入偷,直接訪問會(huì)給使用者、或者系統(tǒng)結(jié)構(gòu)帶來很多的麻煩械哟。

為其他對(duì)象提供一種代理以控制(隔離疏之,使用接口)對(duì)這個(gè)對(duì)象的訪問。
——《設(shè)計(jì)模式》GoF

Proxy的UML

結(jié)構(gòu)看是很簡(jiǎn)單暇咆,但實(shí)際使用的情況可能會(huì)很復(fù)雜锋爪。

由于某種原因,用戶程序不能直接訪問RealSubject對(duì)象糯崎,那么他需要使用一個(gè)代理類Proxy來代理的訪問RealSubject對(duì)象。

以下就是簡(jiǎn)單的一種

class ISubject{
public:
    virtual void process();
};


class RealSubject: public ISubject{
public:
    virtual void process(){
        //....
    }
};

class ClientApp{
    
    ISubject* subject;
    
public:
    
    ClientApp(){
        subject=new RealSubject();
    }
    
    void DoTask(){
        //...
        subject->process();
        
        //....
    }
};


class ISubject{
public:
    virtual void process();
};


//Proxy的設(shè)計(jì)
class SubjectProxy: public ISubject{
    
    
public:
    virtual void process(){
        //對(duì)RealSubject的一種間接訪問
        //....
    }
};

class ClientApp{
    
    ISubject* subject;
    
public:
    
    ClientApp(){
        subject=new SubjectProxy();
    }
    
    void DoTask(){
        //...
        subject->process();
        
        //....
    }
};
  • 要點(diǎn)總結(jié)
    “增加一層間接層”是軟件系統(tǒng)中對(duì)許多復(fù)雜問題的一種常見解決方案河泳。在面向?qū)ο笙到y(tǒng)中沃呢,直接使用某些對(duì)象會(huì)帶來很多問題,作為間接層的Proxy對(duì)象便是解決這一問題的常用手段拆挥。
    具體Proxy設(shè)計(jì)模式的實(shí)現(xiàn)方法薄霜、實(shí)現(xiàn)粒度都相差很大某抓,有些可能對(duì)單個(gè)對(duì)象做細(xì)粒度的控制,如copy-on-write技術(shù)惰瓜,有些可能對(duì)組建模塊提供抽象代理層否副,在架構(gòu)層次對(duì)對(duì)象做proxy
    proxy并不一定要求保持接口完整的一致性,只要能夠?qū)崿F(xiàn)間接控制崎坊,有時(shí)候損及一些透明性是可以接受的备禀。

適配器(Adapter)

將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另一個(gè)接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作奈揍。
——《設(shè)計(jì)模式》GoF

  • 動(dòng)機(jī)
    在軟件系統(tǒng)中曲尸,由于應(yīng)用環(huán)境的變化,常常需要將“一些現(xiàn)存的對(duì)象”放在新的環(huán)境中應(yīng)用男翰,但是新環(huán)境要求的接口是這些現(xiàn)存對(duì)象所不滿足的另患。
Adapter的UML
//目標(biāo)接口(新接口)
class ITarget{
public:
    virtual void process()=0;
};

//遺留接口(老接口)
class IAdaptee{
public:
    virtual void foo(int data)=0;
    virtual int bar()=0;
};

//遺留類型
class OldClass: public IAdaptee{
    //....
};

//對(duì)象適配器
class Adapter: public ITarget{ //繼承
protected:
    IAdaptee* pAdaptee;//組合
    
public:
    
    Adapter(IAdaptee* pAdaptee){
        this->pAdaptee=pAdaptee;
    }
    
    virtual void process(){
        int data=pAdaptee->bar();
        pAdaptee->foo(data);
        
    }
    
    
};


//類適配器
class Adapter: public ITarget,
               protected OldClass{ //多繼承
               
               
}


int main(){
    IAdaptee* pAdaptee=new OldClass();
    
    
    ITarget* pTarget=new Adapter(pAdaptee);
    pTarget->process();
    
    
}


class stack{  //也符合Adapter的設(shè)計(jì)模式
    deqeue container;
    
};

class queue{  //也符合Adapter的設(shè)計(jì)模式
    deqeue container;
    
};
Adapter的UML

要點(diǎn)總結(jié)
Adapter模式主要應(yīng)用于“希望復(fù)用一些現(xiàn)存的類,但是接口又與服用環(huán)境要求不一致的情況”蛾绎,在遺留代碼復(fù)用昆箕、類庫(kù)遷移等方面非常有用。
GoF23定義了兩種Adapter模式的結(jié)構(gòu)實(shí)現(xiàn):對(duì)象適配器好類適配器租冠。但類適配器采用“多繼承”的實(shí)現(xiàn)方式鹏倘,一般不推薦使用。對(duì)象適配器采用“對(duì)象組合”的方式肺稀,更符合松耦合的精神第股。
Adapter模式可以實(shí)現(xiàn)的非常靈活,不必拘泥于GoF23中定義的兩種結(jié)構(gòu)话原。例如夕吻,完全可以將Adapter模式中的“現(xiàn)存對(duì)象”作為新的接口方法參數(shù),來達(dá)到適配的目的繁仁。

中介者(Mediator)

用一個(gè)中介對(duì)象來封裝(封裝變化)一系列的對(duì)象交互涉馅。中介者使各個(gè)對(duì)象不需要顯示的相互引用(編譯時(shí)依賴 -> 運(yùn)行時(shí)依賴),從而使其耦合松散(管理變化)黄虱,而且可以獨(dú)立的改變他們之間的交互稚矿。

  • 動(dòng)機(jī)
    在軟件構(gòu)建的過程中,勁吹出現(xiàn)多個(gè)多項(xiàng)互相關(guān)聯(lián)交互的情況捻浦,對(duì)象之間常常會(huì)維持一種復(fù)雜的引用關(guān)系晤揣,如果遇到了一些需求的更改,這種直接的飲用關(guān)系將面臨不斷的變化朱灿。在這種情況下昧识,我們可以使用“中介對(duì)象”來管理對(duì)象間的關(guān)聯(lián)關(guān)系,避免相互交互的對(duì)象之間的緊耦合引用關(guān)系盗扒,從而更好地抵御變化跪楞。
GoF定義的中介者UML

這幅圖只是描述了依賴的解耦缀去。通過中間的ConcreteMediator將ConcreteColleague1和ConcreteColleague2進(jìn)行了依賴。從而使得ConcreteColleague1和ConcreteColleague2之間不在直接進(jìn)行依賴甸祭。以此來進(jìn)行解耦缕碎。

要點(diǎn)總結(jié)
將多個(gè)對(duì)象間復(fù)雜的關(guān)聯(lián)關(guān)系解耦,Mediator模式將多個(gè)對(duì)象間的控制邏輯進(jìn)行集中管理池户,變“多個(gè)對(duì)象互相關(guān)聯(lián)”為“多個(gè)對(duì)象和一個(gè)中介者關(guān)聯(lián)”咏雌,簡(jiǎn)化了系統(tǒng)的維護(hù),地獄了可能的變化煞檩。
隨著控制邏輯的復(fù)雜化处嫌,Mediator具體對(duì)象的實(shí)現(xiàn)可能相當(dāng)復(fù)雜。這時(shí)候可以對(duì)Mediator對(duì)象進(jìn)行分解處理斟湃。
Facade模式是解耦系統(tǒng)間(單向)的對(duì)象關(guān)聯(lián)關(guān)系熏迹;Mediator模式是解耦系統(tǒng)內(nèi)各個(gè)對(duì)象之間(雙向)的關(guān)聯(lián)關(guān)系。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凝赛,一起剝皮案震驚了整個(gè)濱河市注暗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌墓猎,老刑警劉巖捆昏,帶你破解...
    沈念sama閱讀 212,080評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異毙沾,居然都是意外死亡骗卜,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門左胞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來寇仓,“玉大人,你說我怎么就攤上這事烤宙”榉常” “怎么了?”我有些...
    開封第一講書人閱讀 157,630評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵躺枕,是天一觀的道長(zhǎng)服猪。 經(jīng)常有香客問我,道長(zhǎng)拐云,這世上最難降的妖魔是什么罢猪? 我笑而不...
    開封第一講書人閱讀 56,554評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮叉瘩,結(jié)果婚禮上膳帕,老公的妹妹穿的比我還像新娘。我一直安慰自己房揭,他們只是感情好备闲,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,662評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捅暴,像睡著了一般恬砂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蓬痒,一...
    開封第一講書人閱讀 49,856評(píng)論 1 290
  • 那天泻骤,我揣著相機(jī)與錄音,去河邊找鬼梧奢。 笑死狱掂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的亲轨。 我是一名探鬼主播趋惨,決...
    沈念sama閱讀 39,014評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼惦蚊!你這毒婦竟也來了器虾?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,752評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤蹦锋,失蹤者是張志新(化名)和其女友劉穎兆沙,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體莉掂,經(jīng)...
    沈念sama閱讀 44,212評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葛圃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,541評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了憎妙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片库正。...
    茶點(diǎn)故事閱讀 38,687評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖尚氛,靈堂內(nèi)的尸體忽然破棺而出诀诊,到底是詐尸還是另有隱情,我是刑警寧澤阅嘶,帶...
    沈念sama閱讀 34,347評(píng)論 4 331
  • 正文 年R本政府宣布属瓣,位于F島的核電站,受9級(jí)特大地震影響讯柔,放射性物質(zhì)發(fā)生泄漏抡蛙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,973評(píng)論 3 315
  • 文/蒙蒙 一魂迄、第九天 我趴在偏房一處隱蔽的房頂上張望粗截。 院中可真熱鬧,春花似錦捣炬、人聲如沸熊昌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)婿屹。三九已至灭美,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間昂利,已是汗流浹背届腐。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜂奸,地道東北人犁苏。 一個(gè)月前我還...
    沈念sama閱讀 46,406評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扩所,于是被迫代替她去往敵國(guó)和親围详。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,576評(píng)論 2 349

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