iT邦幫忙

2023 iThome 鐵人賽

0
自我挑戰組

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

[深入淺出設計模式] Ch9 The iterator and composite patterns (2) - 範例 整合餐廳菜單

  • 分享至 

  • xImage
  •  

上篇講完這個範例的需求,簡單來說我們現在要寫一個通用的介面Iterator,讓Waiter可以方便取得不同資料型態儲存資料的餐廳菜單資訊,用統一的方式去迭代資料。

首先就是介面Iterator

public interface Iterator {
    // 判斷陣列是否有下一個要迭代的物件
    public boolean hasNext();
    // 回傳目前迭代的物件,並讓迭代繼續
    public Object next();
}

DinerMenu實作Iterator後的結果:

public class DinerIterator implements Iterator{
    // 以陣列儲存資料
    protected MenuItem menuItems[];
    // 目前迭代的位置(編號)
    protected int position;
    protected int numOfItems;
    public DinerIterator(MenuItem []menuItems, int numOfItems){
        this.menuItems = menuItems; 
        this.numOfItems = numOfItems;
        position = 0;
    }
    
    public boolean hasNext(){
        if(position < numOfItems || menuItems[position] != null){
            return true;
        }
        return false;
    }

    public MenuItem next(){
        MenuItem nextItem = this.menuItems[position];
        position ++;
        return nextItem;
    }
}

類別DinerMenu要增加以下方法才能進行迭代

public DinerIterator createIterator(){
    return new DinerIterator(menuItems, numOfItems);
}

public boolean hasNext(){
    if(this.position < numOfItems || this.menuItems[position] != null){
        return true;
    }
    return false;
}

public MenuItem next(){
    MenuItem nextItem = this.menuItems[position];
    position ++;
    return nextItem;
}

另一邊的DinerMenu是用java的類別ArrayList來儲存資料,而ArrayList本身就有函數iterator()可以回傳一個iterator,所以不需要去實作我們自己定義的介面Iterator(),只要新增以下方法即可:

public ArrayList<MenuItem> getMenuItems(){
    return this.menuItems;
}

public Iterator<MenuItem> createIterator(){
    return menuItems.iterator();
}

最重要的Waiter()就是要去實作這些迭代邏輯的類別(給客人看指定的菜單):

public class Waiter {
    DinerMenu dinerMenu;
    PancakeHouseMenu pancakeHouseMenu;

    public Waiter(DinerMenu dinerMenu, PancakeHouseMenu pancakeHouseMenu){
        this.dinerMenu = dinerMenu;
        this.pancakeHouseMenu = pancakeHouseMenu;
    }    
    // 印出 PancakeHouseMenu
    public void showBreakfastMenu(){
        System.out.println("PancakeHouse Menu:");
        java.util.Iterator<MenuItem> pancakeIter = this.pancakeHouseMenu.createIterator();
        
        // java的類別Iterator就有hasNext()、next()的方法可以用
        while(pancakeIter.hasNext()){
            MenuItem item = pancakeIter.next();
            String vegan =  "(X)";
            if(item.isVegetarian()){
                vegan = "(V)";
            }
            System.out.println(item.getName() + " - $" + item.getPrice() + vegan);
        }
    }
    // 印出DinerMenu
    public void showLunchMenu(){
        DinerIterator dinerIter = this.dinerMenu.createIterator();
        System.out.println("Diner Menu:");
        // 實作DinerIterator的hasNext()、next()方法
        while(dinerIter.hasNext()){
            MenuItem item = dinerIter.next();
            String vegan =  "(X)";
            if(item.isVegetarian()){
                vegan = "(V)";
            }
            System.out.println(item.getName() + " - $" + item.getPrice() + vegan);
        }
    }

    public void showMenus(){
        System.out.println("< Menu >");
        showBreakfastMenu();
        System.out.println("--------------------");
        showLunchMenu();
    }

    public void showVegetarianMenus(){
        System.out.println("< Vegan Menu >");
        System.out.println("PancakeHouse Menu:");
        java.util.Iterator<MenuItem> pancakeIter = this.pancakeHouseMenu.createIterator();
        while(pancakeIter.hasNext()){
            MenuItem item = pancakeIter.next();
            if(item.isVegetarian()){                
                System.out.println(item.getName() + " - $" + item.getPrice());
            }        
        }
        System.out.println("--------------------");
        DinerIterator dinerIter = this.dinerMenu.createIterator();
        System.out.println("Diner Menu:");
        while(dinerIter.hasNext()){
            MenuItem item = dinerIter.next();
            if(item.isVegetarian()){                
                System.out.println(item.getName() + " - $" +item.getPrice());
            }
        }
    }
}

最後來實際跑一次看看結果:

public static void main(String arg[]){
    PancakeHouseMenu pancakeMenu = new PancakeHouseMenu();       
    DinerMenu dinerMenu = new DinerMenu();
    Waiter Amy = new Waiter(dinerMenu, pancakeMenu);
    Amy.showMenus();
    Amy.showVegetarianMenus();
}   

輸出:
https://ithelp.ithome.com.tw/upload/images/20240405/201631786vFnXDIQY4.png


參考資料:

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

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


上一篇
[深入淺出設計模式] Ch9 The iterator and composite patterns (1) - 迭代器模式和組合模式
系列文
深入淺出設計模式 (Head First Design Pattern) - 重點整理及範例分享35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言