將處理陣列或是取值方式的邏輯給封裝起來,不需讓使用者直接處理操作取值的邏輯
沒有Iterator Pattern的情況
假設現在有2種菜單, 分別叫做中式料理菜單 與 西式料理菜單
中式料理菜單是用ArrayList的方式儲存菜單項目
美式料理菜單是用Array[]儲存
中式料理菜單
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class ChineseMenu { ArrayList<String> menu;
ChineseMenu() { this.setMenuItem(); }
public void setMenuItem() { this.menu = new ArrayList<>(); this.menu.add("麻婆豆腐"); this.menu.add("豬血糕"); }
public ArrayList<String> getMenu() { return menu; } }
|
美式料理菜單
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class AmericanMenu { String[] menu;
AmericanMenu() { this.menu = new String[3]; this.setMenuItem(); }
public void setMenuItem() { this.menu[0] = "漢堡"; this.menu[1] = "薯條"; this.menu[2] = "炸雞"; }
public String[] getMenu() { return menu; } }
|
接著定義一個類別:服務生,但服務生需要知道要怎麼撈內容, ArrayList與Array的撈法就會不一樣,要寫兩個for loop…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Waitress { ChineseMenu chineseMenu; AmericanMenu americaMenu;
Waitress( ChineseMenu chMenu, AmericanMenu amerMenu ) { this.chineseMenu = chMenu; this.americaMenu = amerMenu; }
public void introduceMenu() { System.out.println("=======介紹中式料理========"); for(String dish: chineseMenu.getMenu()) { System.out.println(dish); } System.out.println("=======介紹美式式料理========"); for(int i=0; i<americaMenu.getMenu().length; i++) { System.out.println(americaMenu.menu[i]); } } }
|
接著呼叫服務生,介紹菜單
1 2 3 4 5 6 7 8 9
| public class main { public static void main(String[] args) { ChineseMenu chineseMenu = new ChineseMenu(); AmericanMenu americanMenu = new AmericanMenu(); Waitress waitress = new Waitress(chineseMenu, americanMenu); waitress.introduceMenu();
} }
|
問題
可以看到服務生必須要了解如何從菜單取出來,變成每一次若又有新的菜單,那每次服務生又得曉得新菜單的取得方式是怎樣,如此一來就得一直增加for loop, 有N個菜單就有N個for loop, 不大好維護。
Iterator模式登場
該模式主要目的:『讓服務生不需知道其取出細節是如何,只要透過一個標準的介面(Iterator),就可以直接呼叫菜單內容』
定義 Iterator 介面
1 2 3 4
| interface Iterator<T> { Boolean hasNext(); T next(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| interface Menu<T> { void setMenuItem(); T getMenu(); }
class ChineseMenu implements Menu<ArrayList<String>> { ArrayList<String> menu;
ChineseMenu() { this.setMenuItem(); }
public void setMenuItem() { this.menu = new ArrayList<>(); this.menu.add("麻婆豆腐"); this.menu.add("豬血糕"); }
public ArrayList<String> getMenu() { return menu; } }
class AmericanMenu implements Menu<String[]> { String[] menu;
AmericanMenu() { this.menu = new String[3]; this.setMenuItem(); }
public void setMenuItem() { this.menu[0] = "漢堡"; this.menu[1] = "薯條"; this.menu[2] = "炸雞"; }
public String[] getMenu() { return menu; } }
|
這時改用實作兩個Iterator類別 ChineseMenuIterator
與AmericanMenuIterator
,負責定義如何取出菜單內容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class ChineseMenuIterator implements Iterator<String> { ArrayList<String> menu; int count = -1;
public ChineseMenuIterator(Menu<ArrayList<String>> menu) { this.menu = menu.getMenu(); }
public Boolean hasNext() { if (count + 1 >= menu.size()) { return false; } return true; }
public String next() { count++; return this.menu.get(count); } }
class AmericanMenuIterator implements Iterator<String> { String[] menu; int count = -1;
public AmericanMenuIterator(Menu<String[]> menu) { this.menu = menu.getMenu(); }
public Boolean hasNext() { if (count + 1 >= menu.length) { return false; } return true; }
public String next() { count++; return this.menu[count]; } }
|
這時回到服務生,若要介紹菜單內容的話,只要使用上面定義的 ChineseMenuIterator
與AmericanMenuIterator
, 就可以直接取出菜單項目內容了,服務生不需要在曉得要怎麼處理撈取的細節,看到一堆for loop了
Waitress class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Waitress { ChineseMenu chineseMenu; AmericanMenu americaMenu;
ChineseMenuIterator chineseMenuIterator; AmericanMenuIterator americanMenuIterator; Waitress( ChineseMenu chMenu, AmericanMenu amerMenu, ChineseMenuIterator chineseMenuIterator, AmericanMenuIterator americanMenuIterator ) { this.chineseMenu = chMenu; this.americaMenu = amerMenu; this.chineseMenuIterator = chineseMenuIterator; this.americanMenuIterator = americanMenuIterator; }
public void introduceMenu() { System.out.println("=======介紹中式料理========"); while(chineseMenuIterator.hasNext()) { System.out.println(chineseMenuIterator.next()); } System.out.println("=======介紹美式料理========"); while(americanMenuIterator.hasNext()) { System.out.println(americanMenuIterator.next()); } } }
|
再度呼叫服務生介紹菜單
Main class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class main { public static void main(String[] args) { ChineseMenu chineseMenu = new ChineseMenu(); ChineseMenuIterator chineseMenuIterator = new ChineseMenuIterator(chineseMenu); AmericanMenu americanMenu = new AmericanMenu(); AmericanMenuIterator americanMenuIterator = new AmericanMenuIterator(americanMenu); Waitress waitress = new Waitress( chineseMenu, americanMenu, chineseMenuIterator, americanMenuIterator); waitress.introduceMenu(); } }
|
小結
透過Iterator介面定義如何實作抽取資料結構的內容,讓使用者可以不用費心去了解要怎麼取得,直接呼叫已經有實作Iterator介面的class
備註
Collection 類別中其實就已經定義了Iterator介面,不過為了介紹反覆器模式,故在ArrayList中簡單實作了Iterator介面內容
Reference: https://docs.oracle.com/javase/8/docs/api/java/util/Iterator.html