適配器模式(Adapter Pattern)

1. 介紹

1.1 模式說明

定義一個(gè)包裝類藐俺,用于包裝不兼容接口的對(duì)象。

  1. 包裝類 = 適配器Adapter;
  2. 被包裝對(duì)象 = 適配者Adaptee = 被適配的類小压。

1.2 定義

將一個(gè)類的接口轉(zhuǎn)換成客戶希望的另外一個(gè)接口壤靶。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作缚俏。

適配器模式的兩種形式:類的適配器模式 & 對(duì)象的適配器模式

2. 類的適配器模式

2.1 UML類圖 & 組成講解

類的適配器模式UML.jpg
  • Target:期待得到的接口(目標(biāo)角色)
  • ConcreteTarget:具體目標(biāo)類,具有目標(biāo)的普通功能
  • Adaptee:需要適配的接口(源角色)
  • Adapter:把源接口轉(zhuǎn)換成目標(biāo)接口(適配器角色)

2.2 解釋說明

在類的UML類圖可以看出:

  • 沖突:Target期待調(diào)用Request方法贮乳,而Adaptee并沒有(這就是所謂的不兼容了)忧换。
  • 解決方案:為使Target能夠使用Adaptee類里的SpecificRequest方法,故提供一個(gè)中間環(huán)節(jié)Adapter類(繼承Adaptee & 實(shí)現(xiàn)Target接口)向拆,把Adaptee的API與Target的API銜接起來(適配)亚茬。

Adapter與Adaptee是繼承關(guān)系,這決定了這個(gè)適配器模式是類的適配器模式浓恳。

2.3 使用步驟(代碼解析)

步驟1: 創(chuàng)建Target接口

public interface Target {
    //這是源類Adapteee沒有的方法
    void Request();
}

步驟2: 創(chuàng)建源類(Adaptee)

public class Adaptee {
    public void SpecificRequest(){
        System.out.println("源類方法");
    }
}

步驟3: 創(chuàng)建適配器類(Adapter)

//適配器Adapter繼承自Adaptee刹缝,同時(shí)又實(shí)現(xiàn)了目標(biāo)(Target)接口
public class Adapter extends Adaptee implements Target {
    //目標(biāo)接口要求調(diào)用Request()這個(gè)方法名,但源類Adaptee沒有方法Request()
    //因此適配器補(bǔ)充上這個(gè)方法
    //但實(shí)際上Request()還是調(diào)用的源類Adaptee的SpecificRequest()的方法
    //所以適配器只是將SpecificRequest()方法作了一層包裝處理颈将,兼容成了可以調(diào)用的Request()的Target而已
    @Override
    public void Request() {
        this.SpecificRequest();
    }
}

步驟4:定義具體使用目標(biāo)類梢夯,并通過Adapter類調(diào)用所需要的方法從而實(shí)現(xiàn)目標(biāo)

public class AdapterPattern {
    public static void main(String[] args){
        Target mAdapter = new Adapter();
        mAdapter.Request();//會(huì)打印輸出:源類方法
    }
}

2.4 實(shí)例講解

接下來我用一個(gè)實(shí)例來對(duì)類的適配器模式進(jìn)行更深一步的介紹。

a. 實(shí)例概況

  • 背景:小成買了一個(gè)進(jìn)口的電視機(jī)晴圾。
  • 沖突:進(jìn)口電視機(jī)要求電壓(110V)與國(guó)內(nèi)插頭標(biāo)準(zhǔn)輸出電壓(220V)不兼容颂砸。
  • 解決方案:通過適配器將插頭輸出的220V轉(zhuǎn)變成110V。

b. 使用步驟

步驟1: 創(chuàng)建Target接口(期待得到的插頭):能輸出110V電壓

public interface Target {
    //將220V轉(zhuǎn)換輸出110V方法
    void Convert_110v();
}

步驟2: 創(chuàng)建源類(國(guó)內(nèi)輸出220V電壓的插頭)

public class PowerPort220V {
    //國(guó)內(nèi)輸出220V電壓的插頭
    public void Output_220v(){}
}

步驟3: 創(chuàng)建適配器類(Adapter)

public class Adapter220V extends PowerPort220V implements Target {
    @Override
    public void Convert_110v() {
        this.Output_220v();
    }
}

步驟4: 進(jìn)口電視機(jī)類

public class ImportedTv {
    //進(jìn)口電視機(jī)需要傳入目標(biāo)110V電壓進(jìn)行供電才能正常運(yùn)行
    public void Work(Target target) {
        System.out.println("進(jìn)口電視正常運(yùn)行");
    }
}

步驟5: 使用

public class AdapterPattern {
    public static void main(String[] args){
        Target mAdapter220V = new Adapter220V();
        ImportedTv mImportedTv = new ImportedTv();
        //用戶拿著進(jìn)口機(jī)器插上適配器(調(diào)用Convert_110v()方法)
        //再將適配器插上原有插頭(Convert_110v()方法內(nèi)部調(diào)用Output_220v()方法)
        //適配器只是對(duì)國(guó)內(nèi)220V電壓進(jìn)行轉(zhuǎn)換疑务,轉(zhuǎn)換成進(jìn)口電視機(jī)能正常使用的110V電壓沾凄,但本質(zhì)還是使用國(guó)內(nèi)220V進(jìn)行供電
        mAdapter220V.Convert_110v();
        mImportedTv.Work(mAdapter220V);//會(huì)打印輸出:進(jìn)口電視正常運(yùn)行
    }
}

3. 對(duì)象的適配器模式

與類的適配器模式不同的是,對(duì)象的適配器模式不是使用繼承關(guān)系連接到Adaptee類知允,而是使用委派關(guān)系連接到Adaptee類撒蟀。

3.1 UML類圖

對(duì)象的適配器模式UML.jpg

Adapter與Adaptee是委派關(guān)系,即通過在Adapter的構(gòu)造方法中傳入具體需要適配的對(duì)象Adaptee温鸽,這決定了適配器模式是對(duì)象的適配器模式保屯。

3.2 使用步驟(代碼解析)

步驟1: 創(chuàng)建Target接口

public interface Target {
    //這是源類Adapteee沒有的方法
    void Request();
}

步驟2: 創(chuàng)建源類(Adaptee)

public class Adaptee {
    public void SpecificRequest(){
        System.out.println("源類方法");
    }
}

步驟3: 創(chuàng)建適配器類(Adapter)(不再用繼承而是委派)

public class Adapter implements Target {
    // 直接關(guān)聯(lián)被適配類
    private Adaptee adaptee;
    //通過構(gòu)造函數(shù)傳入具體需要適配的對(duì)象
    public Adapter (Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    @Override
    public void Request() {
        // 這里是使用委派的方式完成特殊功能
        this.adaptee.SpecificRequest();
    }
}

步驟4:定義具體使用目標(biāo)類手负,并通過Adapter類調(diào)用所需要的方法從而實(shí)現(xiàn)目標(biāo)

public class AdapterPattern {
    public static void main(String[] args){
        Target mAdapter = new Adapter(new Adaptee());
        mAdapter.Request();//會(huì)打印輸出:源類方法
    }
}

4. 優(yōu)缺點(diǎn)和兩種方式的適配器比較

4.1 優(yōu)點(diǎn)

  • 更好的復(fù)用性:系統(tǒng)需要使用現(xiàn)有的類,而此類的接口不符合系統(tǒng)的需要姑尺。那么通過適配器模式就可以讓這些功能得到更好的復(fù)用竟终。
  • 透明、簡(jiǎn)單:客戶端可以調(diào)用同一接口切蟋,因而對(duì)客戶端來說是透明的统捶。這樣做更簡(jiǎn)單 & 更直接
  • 更好的擴(kuò)展性:在實(shí)現(xiàn)適配器功能的時(shí)候,可以調(diào)用自己開發(fā)的功能柄粹,從而自然地?cái)U(kuò)展系統(tǒng)的功能喘鸟。
  • 解耦性:將目標(biāo)類和適配者類解耦,通過引入一個(gè)適配器類重用現(xiàn)有的適配者類驻右,而無需修改原有代碼
  • 符合開放-關(guān)閉原則:同一個(gè)適配器可以把適配者類和它的子類都適配到目標(biāo)接口什黑;可以為不同的目標(biāo)接口實(shí)現(xiàn)不同的適配器,而不需要修改待適配類

4.2 缺點(diǎn)

  • 過多的使用適配器堪夭,會(huì)讓系統(tǒng)非常零亂愕把,不易整體進(jìn)行把握。

4.3 比較

  • 類的適配器模式使用方便森爽,代碼簡(jiǎn)化恨豁;而對(duì)象的適配器模式使用復(fù)雜,需要引入對(duì)象實(shí)例爬迟。
  • 類的適配器模式高耦合圣絮,靈活性低,使用對(duì)象繼承的方式雕旨,是靜態(tài)的定義方式;而對(duì)象的適配器模式靈活性高捧请、低耦合凡涩,采用 “對(duì)象組合”的方式,是動(dòng)態(tài)組合方式疹蛉。

5. 使用建議

建議盡量使用對(duì)象的適配器模式活箕,多用合成/聚合、少用繼承可款。

6. 感謝

適配器模式(Adapter Pattern)- 最易懂的設(shè)計(jì)模式解析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末育韩,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子闺鲸,更是在濱河造成了極大的恐慌筋讨,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件摸恍,死亡現(xiàn)場(chǎng)離奇詭異悉罕,居然都是意外死亡赤屋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門壁袄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來类早,“玉大人,你說我怎么就攤上這事嗜逻∩В” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵栈顷,是天一觀的道長(zhǎng)逆日。 經(jīng)常有香客問我,道長(zhǎng)妨蛹,這世上最難降的妖魔是什么屏富? 我笑而不...
    開封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蛙卤,結(jié)果婚禮上狠半,老公的妹妹穿的比我還像新娘。我一直安慰自己颤难,他們只是感情好神年,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著行嗤,像睡著了一般已日。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上栅屏,一...
    開封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天飘千,我揣著相機(jī)與錄音,去河邊找鬼栈雳。 笑死护奈,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的哥纫。 我是一名探鬼主播霉旗,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼蛀骇!你這毒婦竟也來了厌秒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤擅憔,失蹤者是張志新(化名)和其女友劉穎鸵闪,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體暑诸,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡岛马,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年棉姐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片啦逆。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡伞矩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出夏志,到底是詐尸還是另有隱情乃坤,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布沟蔑,位于F島的核電站湿诊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏瘦材。R本人自食惡果不足惜厅须,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望食棕。 院中可真熱鬧朗和,春花似錦、人聲如沸簿晓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)憔儿。三九已至忆植,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谒臼,已是汗流浹背朝刊。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蜈缤,地道東北人坞古。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像劫樟,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子织堂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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