文章出處

適配器模式(Adapter Pattern),別名Wrapper。

適配器模式分為兩種:對象適配器模式;類適配器模式。

理解類圖需要知道的一些基本名詞和符號:UML類圖的幾個名詞及對應符號

對象適配器模式

Client想要調用某個具體Adaptee的方法,來實現某個功能A。最直接的做法是將Adaptee作為參數傳入,然后讓Client創建一個方法去調用。
如果Client也想調用另一個具體Adaptee的方法,也實現某個功能A。此時再將Adaptee作為參數傳入,然后讓Client創建一個方法去調用。
……
當Client想調用一百個類(甚至不止這些)的方法,來實現同一個功能A,那不就得添加一百個方法?真這么做,這個類就太臃腫了。并且,在某個具體的系統,極大部分的方法都不會被用到。

那么,提取出一個接口(Target),并讓Client調用這個接口的方法不就行了嗎?這樣Client就不需要為某個具體的類添加方法。 問題就這樣解決了,但還沒結束。

既然有一個接口,那么不就意味著每個具體Adaptee都要實現這個接口了么?最理想的情況是,這些類剛好那個被調用的方法的方法名是相同的,直接加個implements xxx就行了(前提是你被允許修改這些類的代碼)。

當然,現實并不是這么理想。它們的方法名往往不同,而你也不被允許修改它們的代碼,更不用說去這些類里面去實現這些方法。

那TM怎么辦?

先把已知條件整理出來:已知Client會調用Target接口的某個方法,但是具體類的方法名與接口的方法名不匹配,不能讓具體類實現Target接口并傳入Client。
問:如何讓Client只調用Target接口的方法而間接地調用到具體類的方法?

答:創建一個類(MyAdapter),這個類里有一個方法,其方法名與Target定義的方法名完全一致(假設為sayHello())。接著將具體的類(假設為 RudeMan)傳入這個新建的類,在 sayHello() 里面調用具體類的方法(假設為 sayFuck())。這就相當于給RudeMan的sayFuck()方法包裝了另一個名字。
既然MyAdapter的方法名與Target定義的一致,那么就可以加上implements xxx了。

public class MyAdapter implements Target {
    private RudeMan rudeMan = null;
    
    public MyAdapter(RudeMan man) {
        rudeMan = man;
    }
    
    public void sayHello() {
        rudeMan.sayFuck();
    }
}

這時,MyAdapter類相當于是一個轉接口,將具體類RudeMan的具體方法包裝成另一個名字。并且MyAdapter實現了Target接口,可以傳入Client供其調用。

類適配器模式

由于類適配器模式有時需要多重繼承,而JAVA不支持,所以通常不使用類適配器模式。

對于類適配器模式的方式,你會看到這樣的形式:

public class Adapter extends Adaptee implements Target {
……
}

這里extends是為了調用具體類Adaptee的方法,而implements是為了讓Client調用已被Target定義好的方法。

從UML類圖角度來對比兩者

對象適配器模式:基本聚合
類適配器模式:泛化


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()