2010年12月14日 星期二

[OO 設計模式] Iterator Pattern : 反覆器/迭代器


前言 :
這裡我們考慮有兩個用來存放 菜單 的類別, 但是因為這兩個類別使用不同的資料結構 (ArrayList vs Array) 來存放, 因此我們需要想一個General 的方法來走訪這兩個類別所包含的菜單內容. 一開始我們先定義一個介面 (Menu) 用來 decouple 使用類別 (Client) 對不同菜單的依賴性, 而該介面定義一個方法返回一個實現的 Iterator 介面的類別. 接著我們就可以透過該類別來走訪Menu, 實際代碼如下 :
- IMenu.java :
  1. package hf.dp.ch09.menu;  
  2.   
  3. import java.util.Iterator;  
  4.   
  5. public interface IMenu {  
  6.     public Iterator createIterator();  
  7. }  
- 菜單一 PancakeHouseMenu.java :
  1. package hf.dp.ch09.menu;  
  2.   
  3. import hf.dp.ch09.MenuItem;  
  4.   
  5. import java.util.*;  
  6.   
  7. public class PancakeHouseMenu implements IMenu{  
  8.     private ArrayList menuItems;  
  9.       
  10.     public PancakeHouseMenu(){  
  11.         menuItems = new ArrayList();  
  12.         addItem("K&B Breakfast""eggs, milk and toss"false2.99);  
  13.         addItem("Waffles""Deep-fried Bacalhau Ball (Macanese)"false3.0);  
  14.     }  
  15.   
  16.     public void addItem(String n, String d, boolean v, double p){  
  17.         menuItems.add(new MenuItem(n, d, v, p));  
  18.     }  
  19.       
  20.     public Iterator createIterator(){return menuItems.iterator();}  
  21. }  
- 菜單二 DinerMenu.java :
  1. package hf.dp.ch09.menu;  
  2.   
  3. import java.util.Iterator;  
  4.   
  5. import hf.dp.ch09.MenuItem;  
  6. import hf.dp.ch09.menu.iterator.DinerMenuIterator;  
  7.   
  8. public class DinerMenu implements IMenu{  
  9.     public static final int MAX_ITEMS = 6;  
  10.     private MenuItem[] menuItems;  
  11.     private int numberOfItem=0;   
  12.       
  13.     public DinerMenu(){  
  14.         menuItems = new MenuItem[MAX_ITEMS];  
  15.         addItem("Calamari","Available in small and regular portions"false12);  
  16.         addItem("Zucchini Fritte","Lightly battered and fried, with roasted garlic aioli"true2.5);  
  17.     }  
  18.       
  19.     public void addItem(String n, String d, boolean v, double p){  
  20.         if(numberOfItem>=MAX_ITEMS){  
  21.             System.out.println("Sorry, menu is full!");  
  22.         } else {  
  23.             menuItems[numberOfItem] = new MenuItem(n,d,v,p);  
  24.             numberOfItem++;  
  25.         }  
  26.     }  
  27.   
  28.     public Iterator createIterator() {  
  29.         return new DinerMenuIterator(menuItems);  
  30.     }     
  31. }  

因為菜單一 使用 java.util.ArrayList 來當作儲存的容器, 因此我們直接呼叫該類別 ArrayList 上的方法 iterator() 就可以拿到 Iterator 了, 對於菜單二因為是使用 Array 來存放, 所以我們自定義一個 Concrete 的 java.util.Iterator 實現類別疊代器(Iterator) :
- DinerMenuIterator.java :
  1. package hf.dp.ch09.menu.iterator;  
  2.   
  3. import java.util.Iterator;  
  4.   
  5. import hf.dp.ch09.MenuItem;  
  6.   
  7. public class DinerMenuIterator implements Iterator{  
  8.     private MenuItem[] menuItems;  
  9.     private int position=0;  
  10.       
  11.     public DinerMenuIterator(MenuItem[] mu){  
  12.         menuItems = mu;  
  13.     }  
  14.   
  15.     @Override  
  16.     public boolean hasNext() {  
  17.         if (menuItems == null || position>=menuItems.length || menuItems[position]==null)  
  18.             return false;  
  19.         else  
  20.             return true;  
  21.     }  
  22.   
  23.     @Override  
  24.     public MenuItem next() {  
  25.         if (menuItems != null && position < menuItems.length) {  
  26.             MenuItem menuItem = menuItems[position];  
  27.             position++;  
  28.             return menuItem;  
  29.         }  
  30.         return null;  
  31.     }  
  32.   
  33.     @Override  
  34.     public void remove() {  
  35.         throw new java.lang.UnsupportedOperationException();          
  36.     }  
  37. }  

最後我們使用一個Waitress 類別, 透過建構子傳入兩個使用不同Collection 類型當作物件容器的菜單, 並透過方法 printMenu() 來走訪菜單內容 :
- Waitress.java 代碼 :
  1. package hf.dp.ch09;  
  2.   
  3. import java.util.Iterator;  
  4. import hf.dp.ch09.menu.DinerMenu;  
  5. import hf.dp.ch09.menu.IMenu;  
  6. import hf.dp.ch09.menu.PancakeHouseMenu;  
  7.   
  8. public class Waitress {  
  9.     IMenu dinerMenu;  
  10.     IMenu pancakeMenu;  
  11.       
  12.     public Waitress(IMenu dm, IMenu pm) {  
  13.         dinerMenu = dm;  
  14.         pancakeMenu = pm;  
  15.     }  
  16.       
  17.     public void printMenu(){  
  18.         System.out.print("Menu\n----------\n[Lunch]\n");  
  19.         printMenu(dinerMenu.createIterator());  
  20.         System.out.print("[Breakfast]\n");  
  21.         printMenu(pancakeMenu.createIterator());  
  22.     }  
  23.       
  24.     private void printMenu(Iterator i){  
  25.         while(i.hasNext()) {  
  26.             MenuItem mi = i.next();  
  27.             System.out.printf("%s, %.2f -- %s\n", mi.getName(), mi.getPrice(), mi.getDescription());  
  28.         }  
  29.     }  
  30.       
  31.     public static void main(String args[]) {  
  32.         Waitress waitress = new Waitress(new DinerMenu(), new PancakeHouseMenu());  
  33.         waitress.printMenu();  
  34.     }  
  35. }  

執行結果 :
Menu
----------
[Lunch]
Calamari, 12.00 -- Available in small and regular portions
Zucchini Fritte, 2.50 -- Lightly battered and fried, with roasted garlic aioli
[Breakfast]
K&B Breakfast, 2.99 -- eggs, milk and toss
Waffles, 3.00 -- Deep-fried Bacalhau Ball (Macanese)

Iterator Pattern 介紹 :
接著我們來看看這裡使用的 Pattern : Iterator Pattern. Iterator 模式分離了集合物件的走訪行為, 抽像出來一個迭代器類別來負責這個走訪, 這樣既可以做到不外洩集.合內部結構, 又可以讓外部程式方便的存取集合內的資料, 底下是該設計模式的定義 :
- Iterator Pattern 定義
The Iterator Pattern provides a way to access the elements of aggregate object sequentially without exposing its underlying representation.

- UML 示意圖 :

補充說明 :
史蒂芬心得筆記 : Design Pattern - Iterator
Iterator在C#、Java等語言中使用的相當普遍,使用Iterator pattern的目的 在於穩藏聚合物件的實作細節,僅提供外界一個可存取聚合物件內部元素的介面,程式只要透過Iterator 介面,即可走訪聚合物件的各個元素...

Wiki : Iterator Pattern
In object-oriented programming, the Iterator pattern is a design pattern in which iterators are used to access the elements of an aggregate object sequentially without exposing its underlying representation. An Iterator object encapsulates the internal structure of how the iteration occurs.
This message was edited 4 times. Last update was at 27/09/2010 18:09:50

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...