適配器模式的三種形式

適配器模式,顧名思義,就是把原本不兼容的接口,通過適配,使之兼容。

舉個生活中簡單的例子,以前的手機內存卡可以取出來,但是想和電腦之間傳輸音樂、視頻等資料不能直接傳輸,需要通過USB讀卡器,然後插入USB接口就可以傳輸了,這個USB讀卡器就相當於適配器。

你經常使用的手機或電腦充電器,也屬於適配器,它將220V的交流電轉換爲手機可用的直流電。下面,以手機充電器爲例講解適配器模式。

適配器模式一般分爲三類:類適配器模式、對象適配器模式、接口適配器模式(缺省適配器模式)

一、類適配器模式

一般手機充電器輸出的直流電壓爲5V,我們把交流電220V稱爲源,希望得到的直流電5V稱爲目標,而充電器即爲適配器。

//源,交流電
public class AC {
    public int outputAC(){
        return 220;
    }
}
//目標接口,直流電
public interface IDC {
    public int outputDC();
}
//適配器
public class ClsAdapter extends AC implements IDC{

    @Override
    public int outputDC() {
        return outputAC()/44;  //直流電爲交流電的電壓值除以44
    }

    public static void main(String[] args) {
        ClsAdapter adapter = new ClsAdapter();
        System.out.println("交流電電壓:"   adapter.outputAC());
        System.out.println("直流電電壓:"   adapter.outputDC());
    }
}

/** 
輸出結果爲:
交流電電壓:220
直流電電壓:5
*/

可以看到,類適配器是通過繼承源類,實現目標接口的方式實現適配的。但是,由於Java單繼承的機制,這就要求目標必須是接口,有一定的侷限性。

二、對象適配器模式

對象適配器,不是繼承源類,而是依據關聯關係,持有源類的對象,這也隱藏了源類的方法。在這裏,適配器和源類的關係不是繼承關係,而是組合關係。

public class ObjAdapter implements IDC {
    //持有源類的對象
    private AC ac;

    public ObjAdapter(AC ac){
        this.ac = ac;
    }

    public int outputAC(){
        return ac.outputAC();
    }

    @Override
    public int outputDC() {
        return ac.outputAC()/44;
    }

    public static void main(String[] args) {
        ObjAdapter adapter = new ObjAdapter(new AC());
        System.out.println("交流電電壓:"   adapter.outputAC());
        System.out.println("直流電電壓:"   adapter.outputDC());
    }
}
//輸出結果同上

三、接口適配器模式

設想,我現在的目標接口有多個方法,可以輸出5V,12V,20V的電壓。按照正常邏輯,設計一個適配器去實現這個接口,很顯然需要實現所有的方法。但是,實際使用中,其實只需要使用其中一個方法就可以了,比如我mac電腦直流電壓20V,只需要實現20V的方法就可以了。

因此,設計一箇中間類去把目標接口的所有方法空實現,然後適配器類再去繼承這個中間類,選擇性重寫我所需要的方法,豈不是更好。代碼如下,

//目標接口,有多個方法
public interface IDCOutput {
    public int output5V();
    public int output12V();
    public int output20V();
}
//中間類,空實現所有方法,這是一個抽象類
public abstract class DefaultAdapter implements IDCOutput {
    @Override
    public int output5V() {
        return 0;
    }

    @Override
    public int output12V() {
        return 0;
    }

    @Override
    public int output20V() {
        return 0;
    }
}
//我的mac電源適配器只需要實現20V的方法即可
public class MacAdatper extends DefaultAdapter {

    private AC ac;

    public MacAdatper(AC ac){
        this.ac = ac;
    }

    @Override
    public int output20V() {
        return ac.outputAC()/11;
    }

    public static void main(String[] args) {
        MacAdatper adatper = new MacAdatper(new AC());
        System.out.println("mac電腦電壓:"   adatper.output20V());
    }
}
//輸出結果:
//mac電腦電壓:20

至於爲什麼中間類使用抽象類,相信你看過我介紹的軟件六大設計原則,就明白了。它需要符合里氏替換原則(儘量基於抽象類和接口的繼承)。

不太明白接口適配模式的童鞋,建議看一下JDK裏邊提供的一個鍵盤監聽適配器KeyAdapter,它就是一個抽象類,去空實現了KeyListener接口的所有方法。你就會感受到這種模式的奧妙。

總結:

  1. 類適配器模式,繼承源類,實現目標接口。
  2. 對象適配器模式,持有源類的對象,把繼承關係改變爲組合關係。
  3. 接口適配器模式,藉助中間抽象類空實現目標接口所有方法,適配器選擇性重寫。

三種模式,各有優缺點,可根據實際情況選擇使用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章