1. 程式人生 > >重走Java設計模式——介面卡模式(Adapter Pattern)

重走Java設計模式——介面卡模式(Adapter Pattern)

介面卡模式

定義

一個類的介面轉換成客戶希望的另外一個介面。介面卡模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。

結構詳解

介面卡模式有類的介面卡模式和物件的介面卡模式兩種不同的形式。

類介面卡模式

類的介面卡模式把適配的類的API轉換成為目標類的API。

類介面卡的結構圖

在這裡插入圖片描述 在圖中我們可以看到Adaptee類並沒有sampleOperation2()方法,而客戶端則期待這個方法。為使客戶端能夠使用Adaptee類,提供一箇中間環節,即類Adapter,把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是繼承關係,這決定了這個介面卡模式是類的: 這個模式涉及到的角色:

  1. 目標(Target):這就是所期待得到的介面。注意:由於這裡討論的是類介面卡模式,因此目標不可以是類。
  2. 目標(Target):這就是所期待得到的介面。注意:由於這裡討論的是類介面卡模式,因此目標不可以是類。
  3. 介面卡(Adaper):介面卡類是本模式的核心。介面卡把源介面轉換成目標介面。顯然,這一角色不可以是介面,而必須是具體類。

類適配的程式碼例項

// 已存在的、具有特殊功能、但不符合我們既有的標準介面的類  
class Adaptee {  
    public void specificRequest() {  
        System.out.println("被適配類具有 特殊功能...");  
    }  
}  


// 目標介面,或稱為標準介面  
interface Target {  
    public void request();  
}  

// 具體目標類,只提供普通功能  
class ConcreteTarget implements Target {  
    public void request() {  
        System.out.println("普通類 具有 普通功能...");  
    }  
}   


// 介面卡類,繼承了被適配類,同時實現標準介面  
class MyAdapter extends Adaptee implements Target{  
    public void request() {  
        super.specificRequest();  
    }  
}   


// 測試類  
public class Client {  
    public static void main(String[] args) {  
        // 使用普通功能類  
        Target concreteTarget = new ConcreteTarget();  
        concreteTarget.request();  

        // 使用特殊功能類,即適配類  
        Target adapter = new MyAdapter();  
        adapter.request();  
    }  
}  
測試結果:
普通類 具有 普通功能...
被適配類具有 特殊功能... 

物件介面卡模式

與類的介面卡模式一樣,物件的介面卡模式把被適配的類的API轉換成為目標類的API,與類的介面卡模式不同的是,物件的介面卡模式不是使用繼承關係連線到Adaptee類,而是使用委派關係連線到Adaptee類。

物件介面卡模式結構圖

在這裡插入圖片描述 在圖中我們可以看出,Adaptee類並沒有sampleOperation2()方法,而客戶端則期待這個方法。為使客戶端能夠使用Adaptee類,需要提供一個包裝(Wrapper)類Adapter。這個包裝類包裝了一個Adaptee的例項,從而此包裝類能夠把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關係,這決定了介面卡模式是物件的。

物件介面卡程式碼例項

// 介面卡類,直接關聯被適配類,同時實現標準介面  
class MyAdapter implements Target{  
    // 直接關聯被適配類  
    private Adaptee adaptee;  

    // 可以通過建構函式傳入具體需要適配的被適配類物件  
    public MyAdapter (Adaptee adaptee) {  
        this.adaptee = adaptee;  
    }  

    public void request() {  
        // 這裡是使用委託的方式完成特殊功能  
        this.adaptee.specificRequest();  
    }  
}  


// 測試類  
public class Client {  
    public static void main(String[] args) {  
        // 使用普通功能類  
        Target concreteTarget = new ConcreteTarget();  
        concreteTarget.request();  

        // 使用特殊功能類,即適配類,  
        // 需要先建立一個被適配類的物件作為引數  
        Target adapter = new MyAdapter(new Adaptee());  
        adapter.request();  
    }  
}  
測試結果:
普通類 具有 普通功能...
被適配類具有 特殊功能... 

類介面卡模式與物件介面卡模式的對比

  1. 類介面卡使用物件繼承的方式,是靜態的定義方式;物件介面卡使用物件組合的方式,是動態組合的方式。
  2. 對於類介面卡,由於介面卡直接繼承了Adaptee,使得介面卡不能和Adaptee的子類一起工作,因為繼承是靜態的關係,當介面卡繼承了Adaptee後,就不可能再去處理 Adaptee的子類了;但是物件介面卡,一個介面卡可以把多種不同的源適配到同一個目標。換言之,同一個介面卡可以把源類和它的子類都適配到目標介面。因為物件介面卡採用的是物件組合的關係,只要物件型別正確,是不是子類都無所謂。
  3. 對於類介面卡,介面卡可以重定義Adaptee的部分行為,相當於子類覆蓋父類的部分實現方法;但是物件介面卡,要重定義Adaptee的行為比較困難,這種情況下,需要定義Adaptee的子類來實現重定義,然後讓介面卡組合子類。雖然重定義Adaptee的行為比較困難,但是想要增加一些新的行為則方便的很,而且新增加的行為可同時適用於所有的源。
  4. 對於類介面卡,僅僅引入了一個物件,並不需要額外的引用來間接得到Adaptee;但是物件介面卡,需要額外的引用來間接得到Adaptee。

介面卡的優缺點

優點

  1. 可以讓任何兩個沒有關聯的類一起執行。;
  2. 提高了類的複用;
  3. 增加了類的透明度;
  4. 靈活性好。

缺點

  1. 過多地使用介面卡,會讓系統非常零亂,不易整體進行把握。比如,明明看到呼叫的是 A 介面,其實內部被適配成了 B 介面的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用介面卡,而是直接對系統進行重構。
  2. 由於 JAVA 至多繼承一個類,所以至多隻能適配一個適配者類,而且目標類必須是抽象類。

使用場景

有動機地修改一個正常執行的系統的介面,這時應該考慮使用介面卡模式。

使用注意事項

介面卡不是在詳細設計時新增的,而是解決正在服役的專案的問題。