學習、探究Java設計模式——適配器模式

前言

在Android開發中,我們會經常遇到ListAdapter、RecyclerViewAdapter等帶有Adapter字樣的類,其實這里就用到了適配器模式,由于適配器模式的使用頻率極高,因此這篇文章就來探究一下適配器模式及其應用場景。

定義

適配器模式,將一個類的接口轉換成客戶端期望的另一個接口。使得兩個沒有關聯的類能夠在適配器的作用下進行合作。

UML類圖

適配器模式劃分為兩種形式:類適配器模式和對象適配器模式。
1、類適配器模式


類適配器模式

由類適配器模式的UML類圖,我們可以知道Adaptee是被適配對象,而Target是目標接口,Adapter則是適配器,我們要實現的是讓Adaptee具有Target接口,即“轉換接口”,客戶端能通過Adaptee使用Target功能。在類適配器模式下,這是通過讓Adapter繼承Adaptee并實現Target接口來實現的(Java不支持多繼承,因此只能實現某一接口)。

2、對象適配器模式


對象適配器模式

對象適配器模式的UML類圖與類的相似,不同之處在于Adapter與Adaptee的關系不再是繼承關系,而是組合關系,Adapter通過持有Adaptee的一個引用并實現Target接口來實現適配器模式。

實現

1、類適配器模式

首先對于一個被適配器,它的代碼如下,它有自己特有的方法,但這不是客戶端所期望的。

public class Adaptee {
    
    public void specificRequest(){
        System.out.println("Adaptee 特有的方法");
    }
}

客戶端所期望的是Adaptee有另外一個功能,即下面Target接口所提供的方法:

public interface Target {

    //客戶端所期望的接口方法
    void request();
}

也就是說,對于一個具體的Adaptee,我們期望它擁有一個它沒有的方法,以達到我們的期望,也即是“接口轉換”,下面就是適配器Adapter,它繼承自Adaptee,實現了Target接口:

public class Adapter extends Adaptee implements Target {

    @Override
    public void specificRequest() {
        super.specificRequest();
    }

    @Override
    public void request() {
        System.out.println("Adaptee 擁有了Target接口的方法,達到了用戶的預期");    
    }
}

2、對象適配器模式

對象適配器模式中,Target接口和Adaptee類與上述代碼相同,不同之處在于Adapter不是繼承Adaptee,而是用一個成員變量去引用它,代碼如下:

public class Adapter  implements Target {

    private Adaptee mAdaptee;
    
    public Adapter(Adaptee adaptee){
        mAdaptee = adaptee;
    }

    @Override
    public void request() {
        //接口轉換的一系列工作,利用mAdaotee的方法、變量等去實現具體需求
        //調用mAdapter.specificRequest()...等
        System.out.println("Adaptee 擁有了Target接口的方法,達到了用戶的預期");
    }
}

舉個例子

在日常生活中,與適配器模式有關的最常見的例子就是電壓的轉換。我們知道,通過電網提供給每個家庭的電壓是交流電壓220V,但是我們給手機、筆記本電腦充電的時候,并不能直接接在220V交流電上,而是需要通過電源適配器來把交流電轉換成直流電,并輸出較低的電壓來使用。這里的電源適配器其實就是用到了適配器模式,比如蘋果手機電源適配器的常用輸出是5V/1A,這就是經過轉換后的電壓,這樣才能安全地給用電器充電。下面我們就用代碼來模擬這一效果。
(1)先看被適配者adaptee,也即是電網提供的AC 220V:

public class PowerGrid {

    /**
     * 電網能夠直接為我們提供220V AC電壓
     * @return
     */
    public int outPutAC220V(){
        return 220;
    }
}

(2)下面就是Target接口,也即是客戶端所期望電網通過某些轉換能夠提供的功能:

public interface VoltageConversion {

    //客戶端期望適配器為我們提供5V和20V的直流電
    int outPutDC5V();
    int outPutDC20V();
}

(3)接著就是電源適配器了,它實現了Target接口,對外提供了5V和20V的直流電壓輸出,它內部實現了電網提供的220V交流電的轉換:

public class VoltageAdapter implements VoltageConversion {

    private PowerGrid mPowerGrid;

    public VoltageAdapter(PowerGrid adaptee){
        mPowerGrid = adaptee;
    }

    /**
     *  如果有需求,適配器需要輸出原來電網能提供的電壓
     */
    public int outPutAC220V(){
        return mPowerGrid.outPutAC220V();
    }

    @Override
    public int outPutDC5V() {
        int voltageFromPowerGrid = mPowerGrid.outPutAC220V();
        System.out.printf("電源適配器正在工作,將%dV交流電轉換成5V直流電...\n",voltageFromPowerGrid);
        return 5;
    }

    @Override
    public int outPutDC20V() {
        int voltageFromPowerGrid = mPowerGrid.outPutAC220V();
        System.out.printf("電源適配器正在工作,將%dV交流電轉換成20V直流電...\n",voltageFromPowerGrid);
        return 20;
    }
}

(4)最后,我們寫一個Test測試類,來測試我們的代碼:

public class AdapterTest {

    public static void main(String args[]){
        PowerGrid powerGrid = new PowerGrid();
        VoltageAdapter adapter = new VoltageAdapter(powerGrid);

        //首先,我們用適配器給蘋果手機充電
        System.out.println("給蘋果手機充電,適配器提供的電壓為:" + adapter.outPutDC5V());

        //接著,我們用適配器給支持快充的手機充電
        System.out.println("給支持QC4.0的手機充電,適配器提供的電壓為:" + adapter.outPutDC20V());
    }
}

運行結果如下圖所示:


運行結果

可以看出,適配器輸出了我們想要的5V和20V,它內部對220V交流電壓進行電壓變換,也即是“接口轉換”,把原本不具備的功能兼容到客戶所需求的功能上了。

適配器模式和裝飾者模式的比較

學習完適配器模式后,讀者可能會覺得適配器模式和之前學習過的裝飾者模式有很多相似之處,因為它們都持有了一個對象的引用(包裝該對象),并且讓這個對象做出了這個對象原本沒有的行為。那它們之間的區別在哪呢?答案是:適配器模式將一個對象包裝起來以改變其接口;而裝飾者模式將一個對象包裝起來以增加新的行為和責任。
筆者認為,二者的突出的重點不同,適配器模式主要是為了改變接口,也即是被適配對象原本就有一個方法,但不適合客戶端使用,為了讓客戶端可以兼容使用到該方法,就利用了適配器把這個方法進行接口轉換,讓客戶可以使用。那上面的電壓轉換的例子來說,就是電網本來就提供了一個220V的電壓輸出,只不過這不符合我們的需求,所以將它轉換成5V,即是進行了所謂的接口轉換。但裝飾者模式,是提供被包裝對象所沒有的方法,比如裝飾者包裝一個電網,它除了能提供220V輸出之外,還能提供計算電費的功能,即是增加了新的行為和責任

好了,這篇文章到這里就結束了。本文主要介紹了適配器模式的概念以及實現方法和具體的例子,最后與裝飾者模式做了比較,希望各位同學能從中獲益。如果可以的話,希望能給我點個贊,謝謝~

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容