iT邦幫忙

2023 iThome 鐵人賽

0
自我挑戰組

深入淺出設計模式 (Head First Design Pattern) - 重點整理及範例分享系列 第 31

[深入淺出設計模式] Ch7 The Adapter Pattern (7) - 【迪米特法則】範例 超市結帳

  • 分享至 

  • xImage
  •  

沒想到從完賽後荒廢了這麼久XD
想說再往下一章看之前 先複習一下前面的觀念
順便實作上篇提到的迪米特法則看看⋯⋯
假設今天要設計一個簡單的超市結帳系統
會需要類別 Item, Receipt, Payment

首先是Item (商品)
非常直觀的包含商品價格與名稱

public class Item {
    public String name;
    public int price;

    public Item(String name, int price){
        this.name = name;
        this.price = price;
    }
}

付款方式的話 我希望有刷卡跟付現兩種選項
所以先定義一個抽象類別

public abstract class Payment {
    protected String info;
    public String getPaymentInfo(){
        return this.info;
    }
}

用到前面策略模式的概念
把不同實作邏輯封裝在類別 Cash, Card

public class Cash extends Payment{
    // 實際支付金額
    public int paidPayment;
    // 找回的金額
    public int change;

    public  Cash(int paidPayment, int cost){
        this.paidPayment = paidPayment;
        change = paidPayment - cost;
        this.info = "\nPayment: Cash";
        this.info += "\nPaid: $" + paidPayment;
        this.info += "\nReturn $" + change;
    }
}
public class Card extends Payment{
    public String bank;
    protected String number;
    protected String csc;

    public Card(String bank, String number, String csc){
        this.bank = bank;
        this.number = number;
        this.csc = csc;
        int len = this.number.length();
        String fourDigits = this.number.substring(len - 4, len);
        this.info = "\nPayment: Card"; 
        this.info += "\nCard number (last 4 digits): " + fourDigits;
    }
}

最後是結帳的流程

public class Checkout {
    protected int total;
    public Receipt receipt;
    protected Payment payment;
    public ArrayList<Item> cart;

    public int getTotal(ArrayList<Item> items){
        for(int i = 0; i < items.size(); i++){
            this.total += items.get(i).price;
        }
        return total;
    }
    public static void main(String args[]){
        Checkout checkout = new Checkout();
        checkout.cart = new ArrayList<Item>();

        Item oranges = new Item("Heirloom Navel Oranges", 125);
        Item frozenFries = new Item("McCain Extra Crispy Classic Fries", 399);
        Item milk = new Item("Shamrock Farms Vitamin D Whole Milk", 169);
        Item rib = new Item("Barbecue Sauce & 6 Boneless Rib-Shaped Patties", 1499);
        Item toner = new Item("Garnier SKINACTIVE Micellar Cleansing Water", 125);
        Item oatMeal = new Item("Organic Apple Cinnamon Instant Oatmeal Packets", 99);

        checkout.cart.add(oranges);
        checkout.cart.add(frozenFries);
        checkout.cart.add(milk);
        checkout.cart.add(rib);
        checkout.cart.add(toner);
        checkout.cart.add(oatMeal);

        int total = checkout.getTotal(checkout.cart);
        checkout.payment = new Cash(4200, total);

        if(checkout.payment != null){
            Receipt receipt = new Receipt(checkout.cart, total, checkout.payment.getPaymentInfo());
            receipt.eReceipt = true;
            receipt.showContent();
        }
        else{
            System.out.println("You haven't pay the bill.");
        }       
    }
}

輸出如下:

===== RECEIPT =====
Items:
Heirloom Navel Oranges $125
McCain Extra Crispy Classic Fries $399
Shamrock Farms Vitamin D Whole Milk $169
Barbecue Sauce & 6 Boneless Rib-Shaped Patties $1499
Garnier SKINACTIVE Micellar Cleansing Water $125
Organic Apple Cinnamon Instant Oatmeal Packets $99

Total: 2416
Payment: Cash
Paid: $4200
Return $1784
Check more info online.

後來我發現 我也有個地方不小心違反了狄米特原則
在結帳過程的

Receipt receipt = new Receipt(checkout.cart, total, checkout.payment.getPaymentInfo());

類別Receipt不需要知道Payment的實作過程
迪米特法則就是強調類別之間互相獨立性
所以只要以參數來傳遞資訊即可
修改成:

String paymentInfo = checkout.payment.getPaymentInfo();
Receipt receipt = new Receipt(checkout.cart, total, paymentInfo);

參考資料:

  1. 《深入淺出設計模式 (Head First Design Patterns) 》
  2. 書中官方程式碼傳送門
  3. 本篇程式碼傳送門

Disclaimer
因為讀的是原文版,所以難免會有翻譯詞不達意或是專有名詞上的差異,有錯誤的話歡迎在留言區一起交流!


上一篇
[深入淺出設計模式] 完賽心得
下一篇
[深入淺出設計模式] Ch8 The Template Method Pattern (1) - 模板模式 範例 製作飲料
系列文
深入淺出設計模式 (Head First Design Pattern) - 重點整理及範例分享35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言