迭代器模式提供了一種方法順序訪問一個聚合物件中的各個元素,而又不暴露其內部實作,
有過Java編程經驗的人對這種模式應該比較熟悉,因為Java內置的許多集合型別:List、Set、Map等都提供了迭代器介面,可以使用統一的方式遍歷集合中的元素,下面將通過一個例子說明迭代器的使用場景,并了解一下迭代器模式的原理,
包子店賣的有包子和飲品,對于包子和飲品的每一個條目,我們用Item來表示,Item只包含name和price兩個欄位:
1 public class Item { 2 private String name; 3 private double price; 4 5 public Item(String name, double price){ 6 this.name = name; 7 this.price = price; 8 } 9 10 // getters and setters ...11 }
由于包子會不定期更新,所以用一個ArrayList來存盤目前所有的包子類別:
1 public class Bun { 2 ArrayList<Item> buns; 3 4 public Bun(){ 5 buns = new ArrayList<>(); 6 7 addBun("鮮肉包子", 1.5); 8 addBun("香菇青菜包子", 1); 9 addBun("魚香肉絲包子", 1.5);10 }11 12 private void addBun(String name, double price){13 Item item = new Item(name, price);14 buns.add(item);15 }16 17 public ArrayList<Item> getBuns(){18 return buns;19 }20 }
而飲品則比較固定,一般不會增加新的型別,所以就假設固定成5種好了,對于這種需求,或許我們會選擇使用陣列來實作:
1 public class Drink { 2 Item[] drinks; 3 int position; 4 private static final int MAX_SIZE = 5; 5 6 public Drink(){ 7 drinks = new Item[MAX_SIZE]; 8 position = 0; 9 10 addDrink("豆漿", 2);11 addDrink("八寶粥", 2);12 addDrink("牛奶", 2.5);13 addDrink("銀耳湯", 3);14 addDrink("豆腐腦", 2);15 }16 17 private void addDrink(String name, double price){18 Item item = new Item(name, price);19 if(position >= MAX_SIZE){20 System.err.println("飲品已經滿了,,,");21 }else{22 drinks[position++] = item;23 }24 }25 26 public Item[] getDrinks(){27 return drinks;28 }29 }
那么,當我們需要輸出早餐店里的所有包子和飲品的時候,需要怎么寫呢?我們發現包子和飲品的底層存盤不一樣,或許都改成ArrayList會簡單很多,但是由于代碼已經寫好了,其他很多地方都會使用上面的代碼,所以冒險修改不是一個好選擇,只能麻煩一些,針對兩種情況分別處理:
1 public void printItems(){ 2 Bun bun = new Bun(); 3 Drink drink = new Drink(); 4 ArrayList<Item> buns = bun.getBuns(); 5 Item[] drinks = drink.getDrinks(); 6 7 //輸出包子 8 for(int i=0; i<buns.size(); i++){ 9 Item item = buns.get(i);10 System.out.println(item.getName() + ", " + item.getPrice());11 }12 13 //輸出飲品14 for(int i=0; i<drinks.length; i++){15 System.out.println(drinks[i].getName() + ", " + drinks[i].getPrice());16 }17 }
輸出如下:
鮮肉包子, 1.5香菇青菜包子, 1.0魚香肉絲包子, 1.5豆漿, 2.0八寶粥, 2.0牛奶, 2.5銀耳湯, 3.0豆腐腦, 2.0
這里的列印邏輯的實作有幾個問題:①列印方法需要知道包子和飲品的底層實作細節,這不滿足封裝的要求;②列印的邏輯不能擴展,如果包子店增加了饅頭型別,而某位程式員打算使用Set來存盤所有的饅頭,那么列印方法必須要同步修改,因此,我們要做的就是隱藏底層的邏輯,對外提供統一的遍歷介面,不管底層采用什么實作,對外保持一致就行,
為了保持遍歷介面的簡單性,我們不打算加入太多的邏輯,具體做法是定義一個迭代器介面,包含next()和hasNext()兩個方法:
1 public interface Iterator {2 boolean hasNext();3 Item next();4 }
為包子和飲品分別定義對應的迭代器:
1 public class BunIterator implements Iterator{ 2 ArrayList<Item> items; 3 int position; 4 5 public BunIterator(ArrayList<Item> items){ 6 this.items = items; 7 position = 0; 8 } 9 10 @Override11 public boolean hasNext() {12 if(items == null || position >= items.size()){13 return false;14 }else{15 return true;16 }17 }18 19 @Override20 public Item next() {21 return items.get(position++);22 }23 24 25 public class DrinkIterator implements Iterator{26 Item[] items;27 int position;28 29 public DrinkIterator(Item[] items){30 this.items = items;31 position = 0;32 }33 34 @Override35 public boolean hasNext() {36 if(position >= items.length || items[position] == null){37 return false;38 }else{39 return true;40 }41 }42 43 @Override44 public Item next() {45 return items[position++];46 }47 }
修改包子和飲品類,只對外提供creatorIterator方法:
1 public class Bun{ 2 ArrayList<Item> buns; 3 4 public Bun(){ 5 buns = new ArrayList<>(); 6 7 addBun("鮮肉包子", 1.5); 8 addBun("香菇青菜包子", 1); 9 addBun("魚香肉絲包子", 1.5);10 }11 12 private void addBun(String name, double price){13 Item item = new Item(name, price);14 buns.add(item);15 }16 17 public Iterator creatorIterator(){18 return new BunIterator(buns);19 }20 }21 22 23 public class Drink {24 Item[] drinks;25 int position;26 private static final int MAX_SIZE = 5;27 28 public Drink(){29 drinks = new Item[MAX_SIZE];30 position = 0;31 32 addDrink("豆漿", 2);33 addDrink("八寶粥", 2);34 addDrink("牛奶", 2.5);35 addDrink("銀耳湯", 3);36 addDrink("豆腐腦", 2);37 }38 39 private void addDrink(String name, double price){40 Item item = new Item(name, price);41 if(position >= MAX_SIZE){42 System.err.println("飲品已經滿了,,,");43 }else{44 drinks[position++] = item;45 }46 }47 48 public Iterator creatorIterator(){49 return new DrinkIterator(drinks);50 }51 }
接下來使用迭代器寫一個新的列印方法:
1 public class TestIterator { 2 3 public static void main(String[] args){ 4 TestIterator test = new TestIterator(); 5 test.printItemsWithIterator(); 6 } 7 8 public void printItemsWithIterator(){ 9 Bun bun = new Bun();10 Drink drink = new Drink();11 Iterator bunIterator = bun.creatorIterator();12 Iterator drinkIterator = drink.creatorIterator();13 printItemsWithIterator(bunIterator);14 printItemsWithIterator(drinkIterator);15 }16 17 public void printItemsWithIterator(Iterator iterator){18 while(iterator.hasNext()){19 Item item = iterator.next();20 System.out.println(item.getName() + ", " + item.getPrice());21 }22 }23 }
輸出如下:
鮮肉包子, 1.5香菇青菜包子, 1.0魚香肉絲包子, 1.5豆漿, 2.0八寶粥, 2.0牛奶, 2.5銀耳湯, 3.0豆腐腦, 2.0
仍然能夠完成列印任務,而且使用迭代器模式使得代碼簡潔了許多,也更容易維護,
以上簡介了迭代器模式的用法,實際上有了Java內部的迭代器實作后,我們不再需要撰寫自己的迭代器,這里是為了展示迭代器的原理才自己實作,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/42131.html
標籤:設計模式
上一篇:設計模式-行為型-觀察者模式
下一篇:行為型設計模式(中)
