設(shè)計模式干貨系列:(七)適配器模式【學(xué)習(xí)難度:★★☆☆☆张吉,使用頻率:★★★★☆】

前言

今天介紹適配器模式齿梁,舉個生活中的例子,我們筆記本用的到充電器其實就是個適配器肮蛹,筆記本電腦的工作電壓是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ù)之巔上有你也有我爆惧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狸页,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子扯再,更是在濱河造成了極大的恐慌芍耘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熄阻,死亡現(xiàn)場離奇詭異斋竞,居然都是意外死亡,警方通過查閱死者的電腦和手機秃殉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進店門坝初,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人复濒,你說我怎么就攤上這事脖卖。” “怎么了巧颈?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵畦木,是天一觀的道長砸泛。 經(jīng)常有香客問我,道長唇礁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任盏筐,我火速辦了婚禮围俘,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘界牡。我一直安慰自己簿寂,他們只是感情好宿亡,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布常遂。 她就那樣靜靜地躺著,像睡著了一般挽荠。 火紅的嫁衣襯著肌膚如雪克胳。 梳的紋絲不亂的頭發(fā)上怪嫌,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天署照,我揣著相機與錄音酗钞,去河邊找鬼来累。 笑死窘奏,一個胖子當(dāng)著我的面吹牛嘹锁,可吹牛的內(nèi)容都是我干的着裹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼摔竿,長吁一口氣:“原來是場噩夢啊……” “哼少孝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起稍走,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤婿脸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后狐树,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡涯曲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年答憔,在試婚紗的時候發(fā)現(xiàn)自己被綠了掀抹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡蓉驹,死狀恐怖揪利,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疟位,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布绍撞,位于F島的核電站得院,受9級特大地震影響傻铣,放射性物質(zhì)發(fā)生泄漏祥绞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一两踏、第九天 我趴在偏房一處隱蔽的房頂上張望兜喻。 院中可真熱鬧,春花似錦虹统、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帽借。三九已至超歌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間巍举,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工蜓谋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炭分,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓观堂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親师痕。 傳聞我的和親對象是個殘疾皇子荐虐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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