Head First 設計模式 —— 07. 適配器模式

思考題

你能想到真實世界中,還有哪些適配器的例子? P236

  • HDMI 轉 VGA 轉換器
  • Type-C 轉 3.5mm 線

適配器模式解析

客戶使用適配器的過程: P241

  1. 客戶通過目標接口調用適配器的方法對適配器發出請求
  2. 適配器使用被適配者接口把請求轉換成被適配者的一個或多個調用接口
  3. 客戶接收到調用的結果,但並未察覺這一切是適配器在起轉換作用(客戶和被適配者是解耦的,一個不知道另一個

思考題

如果我們也需要一個將鴨子轉換成火雞的適配器,我們稱它為 DuckAdapter。請寫下這個類。你如何處理飛行方法(畢竟我們知道鴨子飛得比火雞遠)? P242

public class DuckAdapter implements Turkey {
    Duck duck;
    int count = 0;

    public DuckAdapter(Duck duck) {
        this.duck = duck;
    }

    public void gobble() {
        duck.quack();
    }

    public void fly() {
        ++ count;
        if(count == 5) {
            count = 0;
            duck.fly();
        } else {
            System.out.println("I'm preparing to fly.");
        }
        // 答案用的是隨機數取模的方法,平均下來每調用5次飛一下
    }
}

適配器模式

將一個類的接口,轉換成客戶期望的另一個接口。適配器讓原本接口不兼容的類可以合作無間。 P243
適配器模式

特點
  • 讓客戶從實現的接口解耦 P243
  • 使用對象組合,以修改的接口包裝被適配者 P243
  • 把客戶和接口綁定起來,而不是和實現綁定起來 P243

思考題

對象適配器(使用組合)和類適配器(使用繼承)使用兩種不同的適配方法。這兩種實現的差異如何影響適配器的彈性? P244

對象適配器
  • 更具有彈性,不僅可以適配某個類,還可以適配其任何子類 P247
  • 需要一個被適配者的對象,但可動態變更被適配者
  • 難以覆蓋被適配者的行為,只能通過繼承的方式實現
  • 只暴露目標接口的行為
類適配器
  • 只能適配特定一個類,但不需要重新實現整個被適配者 P247
  • 本身就是一個被適配者的對象,但不能動態變更被適配者
  • 便於直接在適配器內覆蓋被適配者的行為
  • 不僅暴露目標接口的行為,也暴露被適配者的行為

思考題

某些交流電適配器所做的事情不只是改變接口,它們還加了一些其他的特性,例如:電涌保護、指示燈、警報聲等。
如果要你實現這類特性,你要使用什麼模式? P251

  • 裝飾器模式

所思所想

  • 適配器模式也比較常使用,即使沒看過設計模式,憑藉自己的經驗也能寫出來,主要目的就是適配不兼容的接口。有一次為了在兼容原有特化搜索接口的基礎上,增加一個定製化搜索接口,保證一段時間內兩個接口可並存調用,並將一部分特化搜索接口的流量切到定製化搜索接口上,同時又要保證接口調用方無感知,就寫了一個適配器,將特化搜索參數轉換成定製化搜索的參數,並實現部分流量且切入定製化搜索接口。

本文首發於公眾號:滿賦諸機(點擊查看原文) 開源在 GitHub :reading-notes/head-first-design-patterns