迭代器模式(Iterator Pattern)
迭代器模式定义:Iterator Pattern提供一种方法顺序访问一个聚合元素中的各个元素,而又不暴漏内部方法
酒吧提供beer和wine:
public class Bar { private List<String> barMenu; public Bar(){ barMenu = new ArrayList<String>(); barMenu.add("beer"); barMenu.add("wine"); } public List<String> getMenu(){ return barMenu; } }
餐厅提供rice、soup和noodles:
public class Restaurant { private String[] restaurantMenu; public Restaurant(){ restaurantMenu = new String[3]; restaurantMenu[0] = "rice"; restaurantMenu[1] = "soup"; restaurantMenu[2] = "noodles"; } public String[] getMenu(){ return restaurantMenu; } }
现在要将酒吧与餐厅整合为一个点餐系统,在该点餐系统中既能看到酒吧的所有饮品,又能看到餐厅的所有餐点,通常的处理方式为:
public class OrderSystem { private Bar bar; private Restaurant reataurant; public OrderSystem(Bar bar,Restaurant reataurant){ this.bar = bar; this.reataurant = reataurant; } public void printMenu(){ List<String> bMenus = bar.getMenu(); String[] rMenus = reataurant.getMenu(); if(null != bMenus && bMenus.size() > 0){ for(String name : bMenus){ System.out.println(name); } } if(null != rMenus){ for(int i = 0;i < rMenus.length; i++){ if(null != rMenus[i]){ System.out.println(rMenus[i]); } } } }
1,OrderSystem类与具体集合类型(String[]以及List<String>)、具体实现(for循环)耦合
2,OrderSystem类与具体餐厅类耦合,即使这两个餐厅类提供的方法相同
先来考虑问题1,显然我们需要进行封装以隐藏具体集合类型与实现过程
从OrderSystem类中可以看出,其对集合的操作为遍历,那么封装类需要提供方法以使我们可以遍历其封装的不同集合
public interface Iterator { public boolean hasNext(); public Object next() throws Exception; }
public class BarIterator implements Iterator { private List<String> menu; int nextPosition = 0; public BarIterator(List<String> menu){ this.menu = menu; } public boolean hasNext() { if(menu.size() > nextPosition && null != menu.get(nextPosition)){ return true; } return false; } public Object next() throws Exception { if(menu.size() > nextPosition && null != menu.get(nextPosition)){ Object result = menu.get(nextPosition); nextPosition++; return result; } throw new Exception("越界"); } }
public class RestaurantIterator implements Iterator { private String[] menu; int nextPosition = 0; public RestaurantIterator(String[] menu){ this.menu = menu; } public boolean hasNext() { if(menu.length > nextPosition && null != menu[nextPosition]){ return true; } return false; } public Object next() throws Exception { if(menu.length > nextPosition && null != menu[nextPosition]){ Object result = menu[nextPosition]; nextPosition++; return result; } throw new Exception("越界"); } }
public class Bar { private List<String> barMenu; public Bar(){ barMenu = new ArrayList<String>(); barMenu.add("beer"); barMenu.add("wine"); } public Iterator getMenu(){ return new BarIterator(barMenu); } }
public class Restaurant { private String[] restaurantMenu; public Restaurant(){ restaurantMenu = new String[3]; restaurantMenu[0] = "rice"; restaurantMenu[1] = "soup"; restaurantMenu[2] = "noodles"; } public RestaurantIterator getMenu(){ return new RestaurantIterator(restaurantMenu); } }
public class OrderSystem { private Bar b; private Restaurant r; public OrderSystem(Bar b,Restaurant r){ this.b = b; this.r = r; } public void printMenu(){ Iterator bit = b.getMenu(); Iterator rit = r.getMenu(); printMenu(bit); printMenu(rit); } private void printMenu(Iterator it){ try{ while(it.hasNext()){ Object tmp = it.next(); if(null != tmp){ System.out.println(tmp.toString()); } } }catch(Exception e){ System.out.println(e.getMessage()); } } public static void main(String[] args){ Bar b = new Bar(); Restaurant r = new Restaurant(); OrderSystem h = new OrderSystem(b,r); h.printMenu(); } }
封装的遍历方法没有加锁,在多线程环境下是不适用的
看看设计中的Iterator类是不是和java.util.Iterator十分相似?
/* * @(#)Iterator.java 1.27 06/07/24 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util; /** * An iterator over a collection. Iterator takes the place of Enumeration in * the Java collections framework. Iterators differ from enumerations in two * ways: <ul> * <li> Iterators allow the caller to remove elements from the * underlying collection during the iteration with well-defined * semantics. * <li> Method names have been improved. * </ul><p> * * This interface is a member of the * <a href="{@docRoot}/../technotes/guides/collections/index.html"> * Java Collections Framework</a>. * * @author Josh Bloch * @version 1.27, 07/24/06 * @see Collection * @see ListIterator * @see Enumeration * @since 1.2 */ public interface Iterator<E> { /** * Returns <tt>true</tt> if the iteration has more elements. (In other * words, returns <tt>true</tt> if <tt>next</tt> would return an element * rather than throwing an exception.) * * @return <tt>true</tt> if the iterator has more elements. */ boolean hasNext(); /** * Returns the next element in the iteration. * * @return the next element in the iteration. * @exception NoSuchElementException iteration has no more elements. */ E next(); /** * * Removes from the underlying collection the last element returned by the * iterator (optional operation). This method can be called only once per * call to <tt>next</tt>. The behavior of an iterator is unspecified if * the underlying collection is modified while the iteration is in * progress in any way other than by calling this method. * * @exception UnsupportedOperationException if the <tt>remove</tt> * operation is not supported by this Iterator. * @exception IllegalStateException if the <tt>next</tt> method has not * yet been called, or the <tt>remove</tt> method has already * been called after the last call to the <tt>next</tt> * method. */ void remove(); }再来考虑问题2:与具体餐厅类耦合很容易处理-面向接口编程
这里使用java.util.Iterator
不想实现的方法就抛出默认异常,上面的Iterator类源代码中说的很清楚了:
public class RestaurantIterator implements Iterator<String> { private String[] menu; int nextPosition = 0; public RestaurantIterator(String[] menu){ this.menu = menu; } public boolean hasNext() { if(menu.length > nextPosition && null != menu[nextPosition]){ return true; } return false; } public String next(){ if(menu.length > nextPosition && null != menu[nextPosition]){ String result = menu[nextPosition]; nextPosition++; return result; } throw new NoSuchElementException(); } public void remove(){ throw new UnsupportedOperationException(); } }
public interface R { public Iterator<String> getMenu(); }
public class Bar implements R{ private List<String> barMenu; public Bar(){ barMenu = new ArrayList<String>(); barMenu.add("beer"); barMenu.add("wine"); } public Iterator<String> getMenu(){ return barMenu.iterator(); } }
public class Restaurant implements R{ private String[] restaurantMenu; public Restaurant(){ restaurantMenu = new String[3]; restaurantMenu[0] = "rice"; restaurantMenu[1] = "soup"; restaurantMenu[2] = "noodles"; } public Iterator<String> getMenu(){ return new RestaurantIterator(restaurantMenu); } }
public class OrderSystem { private Bar b; private Restaurant r; public OrderSystem(Bar b,Restaurant r){ this.b = b; this.r = r; } public void printMenu(){ Iterator<String> bit = b.getMenu(); Iterator<String> rit = r.getMenu(); printMenu(bit); printMenu(rit); } private void printMenu(Iterator<String> it){ try{ while(it.hasNext()){ Object tmp = it.next(); if(null != tmp){ System.out.println(tmp.toString()); } } }catch(Exception e){ System.out.println(e.getMessage()); } } public static void main(String[] args){ Bar b = new Bar(); Restaurant r = new Restaurant(); OrderSystem h = new OrderSystem(b,r); h.printMenu(); } }List可以自动返回一个封装好的Iterator
/** * Returns an iterator over the elements in this list in proper sequence. * * @return an iterator over the elements in this list in proper sequence */ Iterator<E> iterator();