適配器模式的定義為:將一個類的介面轉換成用戶端期望的另一個介面。適配器讓原本因為介面不相容而無法一起工作的類可以一起工作。
Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces.
適配器模式的意圖(Intent)就是為適配目標介面而轉換已有的介面,一個adapter可以有多個adaptee,淡然adapter也可增加adaptee沒有的功能。
適配器可以有兩種版本,一種是對象適配器,adapter與adaptee是HAS-A的關係;另一種是類適配器,adapter繼承自adaptee,兩種類型各有優缺點。
類適配器需要用到多繼承,target的介面需要public繼承,而adaptee的實現需要private繼承,這樣就可已區分adaptee和target了。
根據《Header First Design Patterns》中的介紹,class dapter必須要用到multiple inheritance,這個應該是不對的吧?
因為adapter實現(implement)了target的介面,繼承(extend)的是adaptee類,因此沒有多繼承依然可以實現class adapter。
適配器根據語言的不同可以有不同的用處,比如two-way class adapter只能在支援多繼承的語言中使用,two-way class adapter可以把適配多個adaptee,
其本質就是adapter的可以重寫實現相同但簽名不同的函數
《Header First Design Patterns》中adapter模式的範例程式碼如下:
其intent是把一個Turkey適配成一個duck。
首先分別定義Duck和Turkey的interface。
public interface Duck { public void quack(); public void fly();}
public interface Turkey { public void gobble(); public void fly();}
然後實現兩個介面
public class MallardDuck implements Duck { public void quack() { System.out.println("Quack"); } public void fly() { System.out.println("I'm flying"); }}
public class WildTurkey implements Turkey { public void gobble() { System.out.println("Gobble gobble"); } public void fly() { System.out.println("I'm flying a short distance"); }}
利用對象適配器把Turkey適配成Duck
public class TurkeyAdapter implements Duck { Turkey turkey; public TurkeyAdapter(Turkey turkey) { this.turkey = turkey; } public void quack() { turkey.gobble(); } public void fly() { for (int i = 0; i < 5; i++) { turkey.fly(); } }}
客戶使用TurkeyAdapter時調用的都是Duck的方法,動作的主體Trukey實際上對用戶端是透明的。
編寫測試驅動:
public class DuckTestDrive { public static void main(String[] args) { MallardDuck duck = new MallardDuck(); WildTurkey turkey = new WildTurkey(); Duck turkeyAdapter = new TurkeyAdapter(turkey); System.out.println("The Turkey says..."); turkey.gobble(); turkey.fly(); System.out.println("\nThe Duck says..."); testDuck(duck); System.out.println("\nThe TurkeyAdapter says..."); testDuck(turkeyAdapter); } static void testDuck(Duck duck) { duck.quack(); duck.fly(); }}
一點小感悟:
學習設計模式必須要搞清楚的一點就是每個模式的意圖(Intent),其實有很多模式在實現上都是類似或者交叉的,而具體細微的差別就體現在他們的意圖上。
本身中文的邏輯性沒有英文好,所以有些句子為了保持邏輯嚴密性,翻譯成中文自然是比較拗口的,所以看懂了並不代表也能把它翻譯出來。