“接口隔離”模式
在組建構(gòu)建過程中凝颇,某些接口之間直接的依賴常常會(huì)帶來很多問題、甚至根本無法實(shí)現(xiàn)疹鳄。采用添加一層間接接口(穩(wěn)定的)拧略,來隔離本來相互緊密關(guān)聯(lián)的接口是一種常見的解決方案
- 典型模式
- Facade
- Proxy
- Adapter
- Mediator
門面模式(Facade)
- 系統(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
結(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ì)象所不滿足的另患。
//目標(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;
};
要點(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)系盗扒,從而更好地抵御變化跪楞。
這幅圖只是描述了依賴的解耦缀去。通過中間的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)系。