迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示。把游走的任务放在迭代器上,而不是聚合上,这样就简化了聚合的接口,也让责任各得其所。
场景:有一家早餐店和一家晚餐店合并成一家餐厅,现对两个餐厅的菜单进行合并,两家菜单都一样,有name,decription,price,vegetarian属性,而早餐店的菜单是存放在List集合中,晚餐店的菜单存放在数组中,并且对晚餐的菜单数量进行了限制,不想品种太多。这时候如果服务员需要打印菜单,就可以写for循环遍历List,并转换成菜单类输出,同样,用for循环遍历数组,那如果有十几家餐厅合并呢,那不是要写十个for循环了吗?这时候,我们就来看看迭代器模式怎么解决这问题的。
首先,我们创建一个菜单项类,表示具体的食物
//菜单项类 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; } // get方法 }
接着我们创建一个迭代器接口,并且让实现早餐迭代器和晚餐迭代器
//迭代器接口 public interface Iterator { //判断是否还有元素 boolean hasNext(); //返回下一个元素 Object next(); } //早餐类迭代器 public class PancakeHouseMenuIterator implements Iterator{ ArrayList items; int position = 0; public PancakeHouseMenuIterator(ArrayList items){ this.items = items; } @Override public Object next(){ MenuItem menuItem = (MenuItem)items.get(position); position ++; return menuItem; } @Override public boolean hasNext() { if(position >= items.size() || items.get(position) == null){ return false; } else{ return true; } } } //晚餐菜单的迭代器 public class DinerMenuIterator implements Iterator{ MenuItem[] items; //记录当前数组变量的位置 int position = 0; public DinerMenuIterator(MenuItem[] items){ this.items = items; } @Override public Object next(){ MenuItem menuItem = items[position]; position ++; return menuItem; } @Override public boolean hasNext() { if(position >= items.length || items[position] == null){ return false; } else{ return true; } } }
然后我们创建菜单接口,让早餐店和晚餐点的菜单实现这个接口
//由于早餐店菜单的方法和晚餐店菜单的方法很类似,所以我们可以定义一个接口来减少Waitress与具体类的依赖,比较我们要针对接口编程,而不针对实现编程 //菜单接口 public interface Menu { public void addItem(String name,String description,boolean vegetarian,double price); public Iterator createIterator(); } public class DinerMenu implements Menu{ //限制晚餐菜单品种个数 static final int MAX_ITEMS = 6; //记录菜单项的长度 int numberOfItems = 0; MenuItem[] menuItems; public DinerMenu(){ menuItems = new MenuItem[MAX_ITEMS]; addItem("火焰牛排","用火焰点缀的牛排",false,98.0); addItem("红烧牛肉面","香辣可口的牛肉面",false,23.5); addItem("土豆丝盖浇饭","酸酸辣辣的土豆丝",true,10.0); addItem("蔬菜沙拉","新鲜蔬菜拌上沙拉酱",true,9.0); } @Override 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("菜单满了,不能添加了!"); } else{ menuItems[numberOfItems] = menuItem; numberOfItems = numberOfItems + 1; } } //加入一个方法创建一个DinerMenuIterator并返回给客户 @Override public Iterator createIterator(){ return new DinerMenuIterator(menuItems); } } //早餐类 public class PancakeHouseMenu implements Menu { ArrayList menuItems; public PancakeHouseMenu(){ //初始化早餐菜单 menuItems = new ArrayList(); addItem("里脊鸡蛋饼","鸡蛋和面粉融合并煎烤而成",false,8.0); addItem("青菜包","新鲜青菜与面粉融合",true,1.5); addItem("豆腐包","丝滑豆腐与面粉融合",true,1.5); addItem("豆浆","现磨黄豆",true,2.5); } @Override public void addItem(String name,String description,boolean vegetarian,double price){ MenuItem menuItem = new MenuItem(name, description, vegetarian, price); menuItems.add(menuItem); } //加入一个方法创建一个PancakeHouseMenuIterator并返回给客户 @Override public Iterator createIterator(){ return new PancakeHouseMenuIterator(menuItems); } }
最后我们还要创建一个服务员类
//服务员类,用来合并菜单 public class Waitress { Menu pancakeHouseMenu; Menu dinerMenu; //我们其实可以把菜单存在一个List传过来,这里为了方便就直接写两个菜单参数了 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("早餐的菜单:"); printMenu(pancakeIterator); System.out.println(); System.out.println("晚餐菜单:"); printMenu(dinerIterator); } //通过迭代器模式,我们只需要一个循环就可以实现那些list、数组、map等这些存储的遍历了 public void printMenu(Iterator iterator){ while(iterator.hasNext()){ MenuItem menuItem = (MenuItem)iterator.next(); System.out.println("名称:" + menuItem.getName() + ",介绍:" + menuItem.getDescription() + ",是否素菜:" +menuItem.isVegetarian() + ",价格:" + menuItem.getPrice()); } } }
好了让我们来编写测试类来进行测试下
public class Test { public static void main(String[] args) { PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu(); DinerMenu dinerMenu = new DinerMenu(); //创建服务员,把菜单传给她 Waitress waitress = new Waitress(pancakeHouseMenu, dinerMenu); //打印菜单 waitress.printMenu(); } }
运行结果如下:
这就是迭代器模式了,就不需要我们写那么多类似的for循环了。
下一节:组合模式