前言
今天介紹適配器模式齿梁,舉個生活中的例子,我們筆記本用的到充電器其實就是個適配器肮蛹,筆記本電腦的工作電壓是20V勺择,而我國的家庭用電是220V,如何讓20V的筆記本電腦能夠在220V的電壓下工作伦忠?就是靠這個充電器搞定的省核。
在軟件開發(fā)中,有時也存在類似這種不兼容的情況昆码,我們也可以像引入一個電源適配器一樣引入一個稱之為適配器的角色來協(xié)調(diào)這些存在不兼容的結(jié)構(gòu)气忠,這種設(shè)計方案即為適配器模式邻储。
正文
適配器模式概念
適配器模式(Adapter Pattern):將一個接口轉(zhuǎn)換成客戶希望的另一個接口,使接口不兼容的那些類可以一起工作旧噪,其別名為包裝器(Wrapper)吨娜。適配器模式既可以作為類結(jié)構(gòu)型模式,也可以作為對象結(jié)構(gòu)型模式淘钟。
適配器模式結(jié)構(gòu)圖
適配器模式有類適配器模式和對象的適配器模式兩種不同的形式宦赠。如下圖所示,左邊是的類的適配器模式(繼承)米母,右邊是對象的適配器模式(引用)袱瓮。
類的適配器模式
類的適配器模式把被適配的類的API轉(zhuǎn)換成目標(biāo)類的API,其靜態(tài)結(jié)構(gòu)圖如下所示爱咬。
在上圖中可以看出尺借,Adaptee類并沒有simpleOperation2()方法,而客戶端則期待這個方法精拟。為使客戶端能夠使用Adaptee類燎斩,提供一個中間環(huán)節(jié),即類Adapter蜂绎,把Adaptee的API與Target類的API銜接起來栅表。Adapter與Adaptee是繼承關(guān)系,這決定了這個適配器模式是類的师枣。
模式所涉及的角色有:
- 目標(biāo)(Target)角色:這就是所期待得到的接口怪瓶。注意,由于這里討論的是類適配器模式践美,因此目標(biāo)不可以是類洗贰。
- 源(Adaptee)角色:現(xiàn)有需要配置的接口。
- 適配器(Adapter)角色:適配器類是本模式的核心陨倡。適配器把源接口轉(zhuǎn)換成目標(biāo)接口敛滋。顯然,這一叫色不可以是接口兴革,而必須是具體類绎晃。
對象的適配器模式
與類的適配器模式一樣,對象的適配器模式把被適配的類的API轉(zhuǎn)換成目標(biāo)類的API杂曲,與類的適配器模式不同的是庶艾,對象的適配器模式不是使用繼承關(guān)系連接到Adaptee類,而是使用委派關(guān)系連接到Adaptee類擎勘。對象的適配器模式的靜態(tài)結(jié)構(gòu)如下圖所示咱揍。
從上圖中可以看出,Adaptee類并沒有simpleOperation2()方法货抄,而客戶端則期待這個方法述召。為使客戶端能夠使用Adaptee類朱转,需要提供一個包裝(Wrapper)類Adapter蟹地。這個包裝類包裝了一個Adaptee的實例积暖,從而此包裝類能夠把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關(guān)系怪与,這決定了這個適配器模式是對象的夺刑。
從上圖可以看出,模式所涉及的角色有:
- 目標(biāo)(Target)角色:這就是所期待的接口分别,目標(biāo)可以是具體的或抽象的類遍愿。
- 源(Adaptee)角色:現(xiàn)有需要適配的接口。
- 適配器(Adapter)角色:適配器類是本模式的核心耘斩。適配器把源接口轉(zhuǎn)換成目標(biāo)接口沼填,顯然,這一角色必須是具體類括授。
代碼示例
類的適配器模式代碼
public interface Target {
/**
* 這是源類也有的方法simpleOperation1
*/
void simpleOperation1();
/**
* 這是源類沒有的方法simpleOperation2
*/
void simpleOperation2();
}
上面給出的是目標(biāo)角色的源代碼坞笙,這個角色是以一個Java接口的形式實現(xiàn)的〖孕椋可以看出薛夜,這個接口聲明了兩個方法:simpleOperation1()和simpleOperation2()。而源角色Adatpee是一個具體類版述,它有一個simpleOperation1()方法梯澜,但是沒有simpleOperation2()方法,如下面代碼清單所示渴析。
public class Adaptee {
/**
* 源類含有方法simpleOperation1
*/
public void simpleOperation1(){};
}
適配器角色Adapter擴展了Adaptee,同時又實現(xiàn)了目標(biāo)接口晚伙。由于Adaptee沒有提供simpleOperation2()方法,而目標(biāo)接口又要求這個方法俭茧,因此適配器角色Adatper實現(xiàn)了這個方法撬腾,如下面代碼清單所示。
public class Adapter extends Adaptee implements Target {
/**
* 由于源類沒有方法simpleOperation2
* 因此適配器類補充上這個方法
*/
@Override
public void simpleOperation2() {
}
}
類的適配器模式的效果:
- 使用一個具體類把源(Adaptee)適配到目標(biāo)(Target)中恢恼。這樣一來民傻,如果源以及源的子類都使用此類適配,就行不通了场斑。
- 由于適配器類是源的子類漓踢,因此可以適配器類中之換掉(Override)源的一些方法。
- 由于只引進了一個適配器類漏隐,因此只有一個路線到目標(biāo)類喧半,使問題得到簡化。
對象的適配器模式代碼
public interface Target {
/**
* 這是源類也有的方法simpleOperation1
*/
void simpleOperation1();
/**
* 這是源類沒有的方法simpleOperation2
*/
void simpleOperation2();
}
上面給出的是目標(biāo)角色的源代碼青责,這個角色是以一個Java接口的形式實現(xiàn)的挺据∪【撸可以看出,這個接口聲明了兩個方法:simpleOperation1()和simpleOperation2()扁耐。而源角色Adapatee是一個具體類暇检,它有一個simpleOperation1()方法,但是沒有simpleOperation2()方法婉称,如下面帶入清單所示块仆。
public class Adaptee {
/**
* 源類含有方法simpleOperation1
*/
public void simpleOperation1(){};
}
適配器類的源代碼如下面代碼清單所示。
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
super();
this.adaptee = adaptee;
}
/**
* 源類有方法simpleOperation1
* 因此適配器類直接委派即可
*/
@Override
public void simpleOperation1() {
adaptee.simpleOperation1();
}
/**
* 源類沒有方法simpleOperation2
* 因此適配器類補充上這個方法
*/
@Override
public void simpleOperation2() {
//write you code here
}
}
對象的適配器模式的效果:
- 一個適配器可以把多種不同的源適配到同一個目標(biāo)王暗。換言之悔据,同一個適配器可以把源類和它的子類都適配到目標(biāo)接口。
- 與類的適配器模式相比俗壹,要想置換源類的方法就不容易科汗。如果一定要置換掉源類的一個或多個方法,就只好先做一個源類的子類绷雏,將源類的方法置換掉头滔,然后再把源類的子類當(dāng)作真正的源進行適配。
- 雖然想要置換源類的方法不容易之众,但是要想增加一些新的方法則方便得很拙毫,而且新增加的方法可同時適用于所有的源。
總結(jié)
適配器模式將現(xiàn)有接口轉(zhuǎn)化為客戶類所期望的接口棺禾,實現(xiàn)了對現(xiàn)有類的復(fù)用缀蹄,它是一種使用頻率非常高的設(shè)計模式,在軟件開發(fā)中得以廣泛應(yīng)用膘婶,在Spring等開源框架缺前、驅(qū)動程序設(shè)計(如JDBC中的數(shù)據(jù)庫驅(qū)動程序)中也使用了適配器模式。
** 1. 主要優(yōu)點**
無論是對象適配器模式還是類適配器模式都具有如下優(yōu)點:
- 將目標(biāo)類和適配者類解耦悬襟,通過引入一個適配器類來重用現(xiàn)有的適配者類衅码,無須修改原有結(jié)構(gòu)。
- 增加了類的透明性和復(fù)用性脊岳,將具體的業(yè)務(wù)實現(xiàn)過程封裝在適配者類中逝段,對于客戶端類而言是透明的,而且提高了適配者的復(fù)用性割捅,同一個適配者類可以在多個不同的系統(tǒng)中復(fù)用奶躯。
- 靈活性和擴展性都非常好,通過使用配置文件亿驾,可以很方便地更換適配器嘹黔,也可以在不修改原有代碼的基礎(chǔ)上增加新的適配器類,完全符合“開閉原則”莫瞬。
具體來說儡蔓,類適配器模式還有如下優(yōu)點:
- 由于適配器類是適配者類的子類郭蕉,因此可以在適配器類中置換一些適配者的方法,使得適配器的靈活性更強喂江。
對象適配器模式還有如下優(yōu)點:
- 一個對象適配器可以把多個不同的適配者適配到同一個目標(biāo)召锈;
- 可以適配一個適配者的子類,由于適配器和適配者之間是關(guān)聯(lián)關(guān)系开呐,根據(jù)“里氏代換原則”烟勋,適配者的子類也可通過該適配器進行適配规求。
** 2. 主要缺點**
類適配器模式的缺點如下:
- 對于Java筐付、C#等不支持多重類繼承的語言,一次最多只能適配一個適配者類阻肿,不能同時適配多個適配者瓦戚;
- 適配者類不能為最終類,如在Java中不能為final類丛塌,C#中不能為sealed類较解;
- 在Java、C#等語言中赴邻,類適配器模式中的目標(biāo)抽象類只能為接口印衔,不能為類,其使用有一定的局限性姥敛。
對象適配器模式的缺點如下:
- 與類適配器模式相比奸焙,要在適配器中置換適配者類的某些方法比較麻煩。如果一定要置換掉適配者類的一個或多個方法彤敛,可以先做一個適配者類的子類与帆,將適配者類的方法置換掉,然后再把適配者類的子類當(dāng)做真正的適配者進行適配墨榄,實現(xiàn)過程較為復(fù)雜玄糟。
** 3. 適用場景**
在以下情況下可以考慮使用適配器模式:
- 系統(tǒng)需要使用一些現(xiàn)有的類,而這些類的接口(如方法名)不符合系統(tǒng)的需要袄秩,甚至沒有這些類的源代碼阵翎。
- 想創(chuàng)建一個可以重復(fù)使用的類,用于與一些彼此之間沒有太大關(guān)聯(lián)的一些類之剧,包括一些可能在將來引進的類一起工作郭卫。
- (對對象的適配器模式而言)在設(shè)計里,需要改變多個已有的子類的接口猪狈,如果使用類的適配器模式箱沦,就要針對每一個子類做一個適配器類,而這不太實際雇庙。
整理的適配器模式思維導(dǎo)圖
用思維導(dǎo)圖畫了份總結(jié)谓形,懶得看文章的也可以直接看圖片灶伊,另外需要源文件的童鞋可以關(guān)注我個人主頁上的公眾號,回復(fù)適配器模式即可獲取源文件網(wǎng)盤地址寒跳。
一直覺得自己寫的不是技術(shù)聘萨,而是情懷,一篇篇文章是自己這一路走來的痕跡童太∶追靠專業(yè)技能的成功是最具可復(fù)制性的,希望我的這條路能讓你少走彎路书释,希望我能幫你抹去知識的蒙塵翘贮,希望我能幫你理清知識的脈絡(luò),希望未來技術(shù)之巔上有你也有我爆惧。