1. 程式人生 > >一天一個設計模式:介面卡模式

一天一個設計模式:介面卡模式

概念:

  介面卡模式是把一個類的介面變成客戶端所期待的另一種介面,從而使原本因介面不匹配而無法在一起工作的兩個類能夠在一起工作。

用途:

  就像插頭轉換器,之前入了switch港版,插頭是英式的,還好附贈一個插頭轉換器,介面卡就相當於這個轉換器。

種類:

  分為類的介面卡與物件的介面卡兩種

 

類介面卡:

  把適配的類的api轉化為目標類的api

上圖中Adaptee沒有2方法,但是客戶端卻期望呼叫2方法。為了客戶端能夠使用Adaptee類,提供中間類Adapter,把Adaptee與Target的api組合起來,Adapter與Adaptee是繼承關係,所以這決定了介面卡是類介面卡。

涉及到的角色:

  目標(Target)角色:這就是所期待得到的介面。注意:由於這裡討論的是類介面卡,因此目標不能是類。

  源(Adapee)角色:現在需要適配的介面。

  介面卡(Adapter)角色:介面卡類是本模式的核心。介面卡把源介面轉化成目標介面,顯然這一角色不可以是介面必須是具體類。

類介面卡程式碼:

public interface Target {
    /**
     * 這是源類Adaptee也有的方法
     */
    public void sampleOperation1(); 
    /**
     * 這是源類Adapteee沒有的方法
     
*/ public void sampleOperation2(); }
public class Adaptee {
    
    public void sampleOperation1(){}

}
public class Adapter extends Adaptee implements Target {
    /**
     * 由於源類Adaptee沒有方法sampleOperation2()
     * 因此介面卡補充上這個方法
     */
    @Override
    public void sampleOperation2() {
        
//寫相關的程式碼 } }

介面卡Adapter擴充套件了源類,也實現了目標介面,且提供了源類沒有的介面的實現。


 

物件介面卡模式

  物件介面卡與類介面卡不同的地方在於,物件介面卡採用委派的方式將源類與介面卡關聯到一起(類介面卡採用繼承)

 

 

原始碼:

 

public interface Target {
    /**
     * 這是源類Adaptee也有的方法
     */
    public void sampleOperation1(); 
    /**
     * 這是源類Adapteee沒有的方法
     */
    public void sampleOperation2(); 
}

 

public class Adaptee {

    public void sampleOperation1(){}
    
}
public class Adapter {
    private Adaptee adaptee;
    
    public Adapter(Adaptee adaptee){
        this.adaptee = adaptee;
    }
    /**
     * 源類Adaptee有方法sampleOperation1
     * 因此介面卡類直接委派即可
     */
    public void sampleOperation1(){
        this.adaptee.sampleOperation1();
    }
    /**
     * 源類Adaptee沒有方法sampleOperation2
     * 因此由介面卡類需要補充此方法
     */
    public void sampleOperation2(){
        //寫相關的程式碼
    }
}

類介面卡與物件介面卡的權衡

 

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

綜上,儘量以物件介面卡的實現方式為主,多用聚合,少用繼承。當然具體問題具體分析,根據實際需要選擇(個人認為實際上就沒必要對源類進行重寫,如果需要進行重寫直接對源類進行修改就行了,除非是沒有程式碼許可權,不過如果沒有許可權的話,那麼源類對你來講更不可見,也就更沒有重寫的必要了吧。)。

介面卡的優點:

  更好的複用性:

    系統需要使用現有的類,而此類的介面不符合系統的需要,那麼通過介面卡模式可以讓類獲得更好的複用。

  更好的擴充套件性:

    在介面卡實現功能的時候,也可以呼叫自己的功能,從而擴充套件系統的功能。

介面卡的缺點:

  過多的介面卡,會讓系統顯得更加凌亂,不容易把控。

  重構的代價合適的話,確實要比介面卡更合適。