設計模式 - 適配器模式 (Structural Patterns- Adapter Pattern)

前言

適配器模式的使用時機,假想我們今天從台灣要去歐洲旅遊,可是平常常用的充電器根本不能用了(瓦數不同),那該怎麼辦呢?

轉接頭

講白了適配器模式(Adapter)就是一個轉接頭,為什麼程式碼需要用到轉接頭呢?當今天我們系統需要跟十年前開發的系統做連結時,因為此系統已經完全沒人在維護甚至開發那系統的語言已經沒人聽過了,那該如何是好?這時候就可以考慮使用Adpater模式,將新的邏輯資料轉換成舊系統格式輸入進去!

類別圖

  • Client : 呼叫端
  • Target : 要轉換的目標物件
  • Adapter : 適配器介面
    • 可以使用硬轉換 (將每個對應的屬性或功能用Hard Code的方式配對)
    • 也可以使用繼承的方式 (改寫)
  • Adaptee : 要被轉換的物件

不管如何設計物件關係,適配器重點只有一個,創造一個Wrapper(包裝者)包裝要被轉換的物件,並且在此包裝者內撰寫轉換成目標物件的邏輯

範例 (英雄遊戲)

我們新上市的英雄遊戲因為大賣特賣,CEO為了持續增加業績開始併購其他遊戲,並且希望讓其他遊戲的角色可以和目前我們遊戲進行聯名,讓現在正在運行的遊戲玩家可以在遊戲內使用其他款遊戲的角色。

問題:

  • 如何讓它款遊戲角色,與我們的英雄角色攻擊一致?

解決:

  • 設計一個Adpater繼承我們Hero介面
  • 在Adapter中實踐attack方法
  • attack時呼叫UnionHero(聯名英雄)的自己攻擊方法
interface Hero {
    void attack();
}

class MyHero implements Hero {

    @Override
    public void attack() {
        System.out.println("My hero attack");
    }
}

class UnionHero {
    public void touch() {
        System.out.println("Union Hero touch");
    }
}

class HeroAdapter implements Hero {

    private UnionHero unionHero = null;

    HeroAdapter(UnionHero unionHero) {
        this.unionHero = unionHero;
    }

    @Override
    public void attack() {
        unionHero.touch();
    }
}

public class Adapter {
    public static void main(String[] args) {
        Hero hero = new MyHero();
        Hero unionHero = new HeroAdapter(new UnionHero());
        hero.attack();
        unionHero.attack();
    }
}

原始碼

結論

可能使用到Adpater Pattern的時機

  • 當你的物件邏輯牽涉到其他人撰寫的物件時(Adpater在此時除了做包裝,還可以在Adapter作保護自己程式碼的邏輯)
  • 當要接收你物件的對象開出的規格不一樣時,可以嘗試使用Adpater做輸入參數/物件的轉換

留言

這個網誌中的熱門文章

Java Lambda Map篇

(InterviewBit) System Design - Design Cache System

設計模式 - 享元模式 (Structural Patterns - Flyweight Design Pattern)