天天看點

java之對象擴充卡

對象的擴充卡模式

與類的擴充卡模式一樣,對象的擴充卡模式把被适配的類的API轉換成目标類的API,與類的擴充卡模式不同的是,對象的擴充卡模式不是使用繼承關系連接配接到Adaptee類,而是使用委派關系連接配接到Adaptee類。對象的擴充卡模式的靜态結構如下圖所示。

java之對象擴充卡

從上圖中可以看出,Adaptee類并沒有simpleOperation2()方法,而用戶端則期待這個方法。為使用戶端能夠使用Adaptee類,需要提供一個包裝(Wrapper)類Adapter。這個包裝類包裝了一個Adaptee的執行個體,進而此包裝類能夠把Adaptee的API與Target類的API銜接起來。Adapter與Adaptee是委派關系,這決定了這個擴充卡模式是對象的。

從上圖可以看出,模式所涉及的角色有:

  • 目标(Target)角色:這就是所期待的接口,目标可以是具體的或抽象的類。
  • 源(Adaptee)角色:現有需要适配的接口。
  • 擴充卡(Adapter)角色:擴充卡類是本模式的核心。擴充卡把源接口轉換成目标接口,顯然,這一角色必須是具體類。

對象的擴充卡模式代碼

public interface Target {
    /**
     * 這是源類也有的方法simpleOperation1
     */
    void simpleOperation1();

    /**
     * 這是源類沒有的方法simpleOperation2
     */
    void simpleOperation2();
}      

上面給出的是目标角色的源代碼,這個角色是以一個Java接口的形式實作的。可以看出,這個接口聲明了兩個方法:simpleOperation1()和simpleOperation2()。而源角色Adapatee是一個具體類,它有一個simpleOperation1()方法,但是沒有simpleOperation2()方法,如下面帶入清單所示。

public class Adaptee {
    /**
     * 源類含有方法simpleOperation1
     */
    public void simpleOperation1(){};
}      

擴充卡類的源代碼如下面代碼清單所示。

public class Adapter implements Target {


    private Adaptee adaptee;


    public Adapter(Adaptee adaptee) {
        super();
        this.adaptee = adaptee;
    }


    /**
     * 源類有方法simpleOperation1
     * 是以擴充卡類直接委派即可
     */
    @Override
    public void simpleOperation1() {
        adaptee.simpleOperation1();
    }


    /**
     * 源類沒有方法simpleOperation2
     * 是以擴充卡類補充上這個方法
     */
    @Override
    public void simpleOperation2() {
        //write you code here
    }
}      

對象的擴充卡模式的效果:

  • 一個擴充卡可以把多種不同的源适配到同一個目标。換言之,同一個擴充卡可以把源類和它的子類都适配到目标接口。
  • 與類的擴充卡模式相比,要想置換源類的方法就不容易。如果一定要置換掉源類的一個或多個方法,就隻好先做一個源類的子類,将源類的方法置換掉,然後再把源類的子類當作真正的源進行适配。
  • 雖然想要置換源類的方法不容易,但是要想增加一些新的方法則友善得很,而且新增加的方法可同時适用于所有的源。

總結

擴充卡模式将現有接口轉化為客戶類所期望的接口,實作了對現有類的複用,它是一種使用頻率非常高的設計模式,在軟體開發中得以廣泛應用,在Spring等開源架構、驅動程式設計(如JDBC中的資料庫驅動程式)中也使用了擴充卡模式。

** 1. 主要優點**

無論是對象擴充卡模式還是類擴充卡模式都具有如下優點:

  • 将目标類和适配者類解耦,通過引入一個擴充卡類來重用現有的适配者類,無須修改原有結構。
  • 增加了類的透明性和複用性,将具體的業務實作過程封裝在适配者類中,對于用戶端類而言是透明的,而且提高了适配者的複用性,同一個适配者類可以在多個不同的系統中複用。
  • 靈活性和擴充性都非常好,通過使用配置檔案,可以很友善地更換擴充卡,也可以在不修改原有代碼的基礎上增加新的擴充卡類,完全符合“開閉原則”。

具體來說,類擴充卡模式還有如下優點:

  • 由于擴充卡類是适配者類的子類,是以可以在擴充卡類中置換一些适配者的方法,使得擴充卡的靈活性更強。

對象擴充卡模式還有如下優點:

  • 一個對象擴充卡可以把多個不同的适配者适配到同一個目标;
  • 可以适配一個适配者的子類,由于擴充卡和适配者之間是關聯關系,根據“裡氏代換原則”,适配者的子類也可通過該擴充卡進行适配。

** 2. 主要缺點**

類擴充卡模式的缺點如下:

  • 對于Java、C#等不支援多重類繼承的語言,一次最多隻能适配一個适配者類,不能同時适配多個适配者;
  • 适配者類不能為最終類,如在Java中不能為final類,C#中不能為sealed類;
  • 在Java、C#等語言中,類擴充卡模式中的目标抽象類隻能為接口,不能為類,其使用有一定的局限性。
  • 與類擴充卡模式相比,要在擴充卡中置換适配者類的某些方法比較麻煩。如果一定要置換掉适配者類的一個或多個方法,可以先做一個适配者類的子類,将适配者類的方法置換掉,然後再把适配者類的子類當做真正的适配者進行适配,實作過程較為複雜。
  • 系統需要使用一些現有的類,而這些類的接口(如方法名)不符合系統的需要,甚至沒有這些類的源代碼。
  • 想建立一個可以重複使用的類,用于與一些彼此之間沒有太大關聯的一些類,包括一些可能在将來引進的類一起工作。
  • (對對象的擴充卡模式而言)在設計裡,需要改變多個已有的子類的接口,如果使用類的擴充卡模式,就要針對每一個子類做一個擴充卡類,而這不太實際。