迭代器模式
提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
迭代器模式把在元素之间游走的责任交给了迭代器,而不是聚合对象。这不仅让聚合的接口和实现变得更简洁,也可以让聚合更专注在它所应该专注的事情上面(也就是管理对象集合),而不必去理会遍历的事情。
下面是具体例子:
菜单项的类:MenuItem.java
package com.designpattern.iterator; public class MenuItem { String name; String description; boolean vegetarian; double price; public MenuItem(String name, String description, boolean vegetarian, double price){ this.name = name; this.description = description; this.vegetarian = vegetarian; this.price = price; } public String getName() { return name; } public String getDescription() { return description; } public boolean isVegetarian() { return vegetarian; } public double getPrice() { return price; } }
package com.designpattern.iterator; import java.util.Iterator; /** * 菜单的共同接口 * */ public interface Menu { public Iterator<?> createIterator(); }
package com.designpattern.iterator; import java.util.ArrayList; import java.util.Iterator; /** * 用ArrayList来存储菜单项,有内嵌的返回迭代器方法,menuItems.iterator(); * createIterator()方法中可以直接返回迭代器,不用自己写迭代器; * */ public class PancakeHouseMenu implements Menu{ ArrayList<MenuItem> menuItems; public PancakeHouseMenu(){ menuItems = new ArrayList<MenuItem>(); addItem("K&B's 薄煎饼早餐", "薄煎饼、清蛋和吐司", true, 2.99); addItem("薄煎饼早餐例餐", "薄煎饼带煎蛋,香肠", false, 2.99); addItem("蓝莓薄煎饼", "新鲜蓝莓和蓝莓糖浆做成的薄煎饼", true, 3.49); addItem("松饼", "松饼,可以选择蓝莓或草莓", true, 3.59); } public void addItem(String name, String description, boolean vegetarian, double price){ MenuItem menuItem = new MenuItem(name, description, vegetarian, price); menuItems.add(menuItem); } // public ArrayList<MenuItem> getMenuItems(){ // return menuItems; // } @Override public Iterator<MenuItem> createIterator() { // TODO Auto-generated method stub return menuItems.iterator(); } }
package com.designpattern.iterator; import java.util.Iterator; /** * 用数组来存储菜单项,没有内嵌的返回迭代器方法; * 需要自己写迭代器:DinerMenuIterator.java,继承自Iterator类。 * */ public class DinerMenu implements Menu{ static final int MAX_ITEMS = 6; int numberOfItems = 0; MenuItem[] menuItems; public DinerMenu(){ menuItems = new MenuItem[MAX_ITEMS]; addItem("素食BLT", "(煎)培根、生菜&西红柿,用麦皮面包做", true, 2.99); addItem("BLT", "培根、生菜&西红柿", false, 2.99); addItem("例汤", "一碗例汤,配土豆沙拉", false, 3.29); addItem("热狗", "热狗、酸菜、上盖芝士", false, 3.05); } public void addItem(String name,String description, boolean vegetarian, double price){ MenuItem menuItem = new MenuItem(name, description, vegetarian, price); if(numberOfItems >= MAX_ITEMS){ System.err.println("Sorry, menu is full! Can't add item to menu."); }else{ menuItems[numberOfItems] = menuItem; numberOfItems +=1; } } // public MenuItem[] getMenuItems(){ // return menuItems; // } @Override public Iterator<Object> createIterator() { // TODO Auto-generated method stub return new DinerMenuIterator(menuItems); } }
package com.designpattern.iterator; import java.util.Iterator; /** * 由于数组没有内嵌的返回迭代器的方法,因此需要写自己的迭代器; * */ public class DinerMenuIterator implements Iterator<Object>{ MenuItem[] list; int position = 0; public DinerMenuIterator(MenuItem[] list){ this.list = list; } @Override public boolean hasNext() { // TODO Auto-generated method stub if(position >= list.length || list[position] == null){ return false; }else{ return true; } } @Override public Object next() { // TODO Auto-generated method stub MenuItem menuItem = list[position]; position += 1; return menuItem; } @Override public void remove() { // TODO Auto-generated method stub if(position <= 0){ throw new IllegalStateException("You can't remove an item until you've done at least one next()."); } if(list[position - 1] != null){ for(int i = position-1;i<(list.length -1);i++){ list[i] = list[i+1]; } list[list.length-1] = null; } } }
package com.designpattern.iterator; import java.util.Iterator; /** * 操作菜单的类 * */ public class Waitress { Menu pancakeHouseMenu; Menu dinerMenu; public Waitress(Menu pancakeHouseMenu, Menu dinerMenu){ this.pancakeHouseMenu = pancakeHouseMenu; this.dinerMenu = dinerMenu; } public void printMenu(){ Iterator<?> pancakeIterator = pancakeHouseMenu.createIterator(); Iterator<?> dinerIterator = dinerMenu.createIterator(); System.out.println("MENU\n----\nBREAKFAST"); printMenu(pancakeIterator); System.out.println("\nLUNCH"); printMenu(dinerIterator); } private void printMenu(Iterator<?> iterator){ while(iterator.hasNext()){ MenuItem menuItem = (MenuItem) iterator.next(); System.out.println(menuItem.getName() + ","); System.out.println(menuItem.getPrice() + "---"); System.out.println(menuItem.getDescription()); } } }
package com.designpattern.iterator; public class Test { public static void main(String[] args) { Menu pancakeHouseMenu = new PancakeHouseMenu(); Menu dinerMenu = new DinerMenu(); Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu); waitress.printMenu(); } }
两个菜单都实现了Menu接口,Waitress类可以直接利用接口引用每一个菜单对象。这样通过“针对接口编程,而不是针对实现编程”,我们就可以减少Waitress类与具体类之间的依赖。
此外,如果想要再添加新的菜单也会变得很容易,只需要按照前面两个菜单类写一个继承Menu接口的菜单类,再在Waitress类中添加菜单类的对象即可。即Waitress类具有更好的扩展性。
JAVA 5包含了一种新形式的for语句,称for/in。这可以让你在一个集合或者一个数组中遍历,而且不需要显式创建迭代器。但需要使用JAVA 5的泛型新特性来确保for/in的类型安全。
但是,迭代器模式还存在一个问题,假如想在菜单中添加子菜单,迭代器模式是不可以实现的,这要用到接下来要将的“组合模式”。