設計模式系列之「適配器模式」

小C:小Y,家里的插孔沒有兩孔的怎么辦?
小Y:so easy,淘寶電源轉換插頭包郵只要九塊九毛九,真的只要九塊九毛九。
......
小C:iPhone x變成Lightning接頭,傳統(tǒng)的耳機會不會用不了?
小Y:又沒有這么牛叉的機,你問這個干啥呢(小Y有點不好的預感?。??買個轉換線唄。
小C:哦,沒事就問問。

后來呢,小Y幾個月只能吃泡面了過日子了,嗚嗚嗚......

其實大家也要學學小Y這種為博紅顏一笑,勒緊褲頭吃泡面的無謂精神(一定要看好自己的信用卡?。?。言歸正傳,現實生活中有各種各樣的適配器,方便至極,那么,適配器這樣的工作,在我們的程序里有嗎?答案是必須的,適配器模式。

文章內容思維導圖

一、基本概念

1.定義

將一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口不匹配而無法在一起工作的兩個類能夠在一起工作。即定義一個包裝類,用于包裝不兼容接口的對象。

2.應用場景
  • 有動機修改一個已經上線的接口時并且不符合你的需求,適配器模式可能是最適合你的模式。
3.角色介紹
通用UML.png
  • Target目標角色

    該角色定義把其他類轉換為何種接口,也就是我們的期望接口。

  • Adaptee源角色

    需要轉換成目標角色的源角色,它是已經存在的、運行良好的類或對象,經過適配器角色的包裝,它會成為一個嶄新的角色。

  • Adapter適配器角色

    適配器模式的核心角色,其他兩個角色都是已經存在的角色,而適配器角色是需要新建立的,它的職責非常簡單:把源角色通過繼承或者類關聯的方法轉換為目標角色。

二、代碼的實現

好了,該是讓這次的主角iPhone差的轉換線出場了(無限心傷中.....)

在這之前還需要知道適配器模式的形式分為:類的適配器模式對象的適配器模式。

1.兩種不同形式適配模式的UML對比

兩者的差別就是一個是通過繼承,一個是通過組合,利用實例的方式去進行

2.兩種不同形式適配模式的代碼實現

(1)兩者實現代碼的相同部分

①iPhone X手機接口(Target接口)

public interface PhoneInterface {  
    /**  
     * Lightning耳機接口
    */  
    void lightningHeadSet();  
}  

②Lightning接口耳機

public class LightningHeadSet implements PhoneInterface {  
    @Override  
    public void lightningHeadSet() {  
        System.out.print("使用Lightning接口的耳機連接。");  
    }  
}  

③傳統(tǒng)耳機接口(源類Adaptee)

public interface TraditionPhoneInterface {   
    /**  
     * 傳統(tǒng)耳機接口  
     */  
    void traditionHeadSet();  
}  

④傳統(tǒng)接口耳機

public class TraditionHeadSet implements TraditionPhoneInterface{  

    @Override  
    public void traditionHeadSet() {  
        System.out.print("使用傳統(tǒng)接口的耳機連接。");  
    }  
}  

(2)類的適配器模式的實現

創(chuàng)建適配器類(繼承傳統(tǒng)耳機(源類)和實現Linghtning接口(Target))

public class HeadSetAdapter extends TraditionHeadSet implements PhoneInterface{  
    @Override  
    public void lightningHeadSet() {  
        super.traditionHeadSet();  
    }  
}  

為什么會去繼承TraditionHeadSet和實現PhoneInterface呢?是因為用戶最終是需要用到Lightning接口去實現聽歌,所以要調用lightningHeadSet(),但是適配器的作用就是讓傳統(tǒng)耳機實現Lightning的轉化,最終用傳統(tǒng)耳機都能夠得到連接。

(3)對象的適配器模式的實現(推薦)

public class ObjectHeadSetAdapter implements PhoneInterface {  

    private TraditionPhoneInterface traditionHeadSet;  

    public ObjectHeadSetAdapter(TraditionPhoneInterface traditionHeadSet) {  
        this.traditionHeadSet=traditionHeadSet;  
    }  

    @Override  
    public void lightningHeadSet() {  
        traditionHeadSet.traditionHeadSet();  
    }  
}  

為什么只實現PhoneInterface接口的理由同上。

(4)客戶端輸出

public class Client {
    public static void main(String[] args){
        //直接通過lightning接口連接
        LightningHeadSet lightningHeadSet=new LightningHeadSet();
        lightningHeadSet.lightningHeadSet();
        //通過類的適配器進行連接
        HeadSetAdapter headSetAdapter=new HeadSetAdapter();
        headSetAdapter.lightningHeadSet();
        //通過對象的適配器進行連接
        TraditionPhoneInterface traditionSet=new TraditionHeadSet();
        ObjectHeadSetAdapter objectHeadSetAdapter=new ObjectHeadSetAdapter(traditionSet);
        objectHeadSetAdapter.lightningHeadSet();
    }
}

輸出的結果為:

①使用Lightning接口的耳機連接。  
②使用傳統(tǒng)接口的耳機連接。  
③使用傳統(tǒng)接口的耳機連接。  

3.對象的適配器 vs 類的適配器

  • 類的適配器中Adapter與Adaptee是繼承關系,因為java是不支持多繼承的,因此不適合出現多個源類;對象的適配器模式不是使用繼承關系連接到Adaptee類,而是使用委派關系連接到Adaptee類,這種關聯的方法可以動態(tài)組合多個源類。
  • 類的適配器是繼承被適配類,所以相對靜態(tài);而對象的適配器包含被適配類,所以相對靈活。
  • 類的適配器通過 Override 來擴展新需求;而對象的適配器因為包含關系所以不能擴展。

三、優(yōu)缺點

1.類的適配器的優(yōu)缺點

(1)優(yōu)點

  • 使用方便,代碼簡化,不需要引入對象實例。

(2)缺點

  • 高耦合,靈活性低。使用對象繼承的方式,是靜態(tài)的定義方式。

2.對象的適配器的優(yōu)缺點

(1)優(yōu)點

  • 靈活性高、低耦合 ,采用 “對象組合”的方式,是動態(tài)組合方式。

(2)缺點

  • 使用復雜,需要引入對象實例。

3.適配器的優(yōu)缺點

(1)優(yōu)點

  • 提高了類的復用度。源角色在原有的系統(tǒng)中可以正常使用,在目標角色中又可以充當新的角色。
  • 增加了類的透明性,客戶端可以調用同一接口,因而對客戶端來說是透明的。
  • 靈活性好。增加刪除不影響原有代碼。
  • 符合開閉原則。

(2)缺點

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

四、總結

在選用適配器模式的時候根據需要來選用合適的實現方式,盡量使用對象的適配器模式,多用動態(tài)組合合、少用繼承

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容