Design Pattern:Adapter Pattern 說明

主要概念:

Client 要使用 CompatibleThing object,但實際的物件介面沒有繼承,因此必須要透過 Adapter 包裝 IncompatibleThing,讓他可以有這樣的介面可以讓 Client 引用。

舉例而言:ShoppingCart 使用 item 項目結帳,但如果我們要直接使用 Hat object 該如何處理?

程式碼如下:

Item Class:

public abstract class Item {
    public abstract String itemName();
    public abstract int itemPrice();
}

Hat Class:

public class Hat { 
    private static final double VAT_PERCENT = 0.2;
    private final String shortName;
    private final String longName;
   
    private final int basePrice;
   
    public Hat(String shortName, String longName, int price) {
        this.shortName = shortName;
        this.longName = longName;
        this.basePrice = price;
    }
   
    public String getShortName() {
        return shortName;
    }
   
    public String getLongName() {
        return longName;
    }
   
    public int getPrice() {
        return (int) (basePrice * (1 + VAT_PERCENT));
    }
}

ShoppingCart Class:

public class ShoppingCart {
   
    private List<Item> items = new LinkedList<>();
   
    public void add(Item item) {
        items.add(item);
    }
   
    public boolean remove(Item item) {
        return items.remove(item);
    }
   
    public long getTotalPrice() {
        long result = 0;
        for (Item item: items) {
            result += item.itemPrice();
        }
        return result;
    }
   
    public String getReceipt() {
        StringBuffer result = new StringBuffer();
        for (Item item: items) {
            result.append(item.itemName() + "\t" + formatMoney(item.itemPrice()) + "\n");
        }
        result.append("----------------------\n");
        result.append("Total:\t\t" + formatMoney(getTotalPrice()) + "\n");
        return result.toString();
    }
   
    private String formatMoney(long money) {
        return "€" + (money / 100) + "." + (money % 100);
    }
}

可以看到 ShoppingCart 只接受 Item object,因此除非 Hat 也要實作 Item 介面,否則不可能傳入到 shoppingCart 中。

解決方案就是建立 Adapter,繼承 Item reference Hat 將他 wrap :

public class HatAdapter extends Item {
   
    private Hat hat;
   
    public HatAdapter(Hat hat) {
        super();
        this.hat = hat;
    }
   
    @Override
    public String itemName() {
        return hat.getShortName();
    }
   
    @Override
    public int itemPrice() {
        return hat.getPrice();
    }
}

如此,就可以將 Hat 傳入到 Adapter ,讓 ShoppingCart 可以直接使用:

public static void main(String[] args) {
     HatAdapter goldenHat = new HatAdapter(new Hat("Golden hat", "Golden hat", 4999));
     HatAdapter pointyHat = new HatAdapter(new Hat("Pointy hat", "Pointy hat", 3000));
     HatAdapter purpleHat = new HatAdapter(new Hat("Purple hat", "Purple hat", 1490));
   
     ShoppingCart cart = new ShoppingCart();
          
     cart.add(goldenHat);
     cart.add(pointyHat);
     cart.add(purpleHat);
          
     cart.remove(pointyHat);
          
     System.out.println(cart.getReceipt());
}

Pattern 架構如下:

有問題嗎?歡迎一起討論喔!