迭代器设计模式 --提供一种方法顺序访问聚合集合里面的元素,而又不暴露其内部的表示
情景 : 煎饼果子屋和普通餐厅要合并了,但又不想改变各自的菜单,现在要求一个java服务员能够按照一定的顺序打印出菜单
思路 : 为了不暴露菜单里面的具体的内容,但又必须拿出菜单,则可以想到迭代器的方式,其实说白了就是c中的指针。。。
我们要做的就是送给这两家店,每家一个迭代器,然后附送这两家店每家一个创建迭代器的方法。。。那么服务员就可打印这两家菜单了
这是菜单项
package javaDesignModede_IteratorMode; public class menuItem { // 每一份菜单项的内容 private String itemName; //菜名 private String description; //描述 private boolean isVegetarian; // 是否是素食 private double price; public menuItem() { } public menuItem(String name, String des, boolean veg, double pri){ this.itemName = name; this.description = des; this.isVegetarian = veg; this.price = pri; } // 为了不暴露内部的信息,我就不适用getter来得到成员变量了 @Override public String toString() { return itemName+price; } }
下面是两家店的具体实现菜单
package javaDesignModede_IteratorMode; import java.util.ArrayList; import java.util.Iterator; /*煎饼屋的菜单实现 * */ public class PanCakeHouseMenu { // 用一个ArrayList来实现它的菜单项 ArrayList<menuItem> menuItems; //在菜单的构造器中每一份都会被添加到菜单集合中 public PanCakeHouseMenu() { addItem("普通煎饼果子", "加上鸡蛋和火腿", false, 7.5); addItem("蓝莓煎饼果子", "加上蓝莓", true, 5.0); addItem("华夫饼", "加上蓝莓和草莓", true, 6.5); } public void addItem(String name, String des, boolean veg, double pri){ menuItem item = new menuItem(name, des, veg, pri); menuItems.add(item); } // 返回煎饼屋的菜单项 public ArrayList<menuItem> getMenuItems(){ return menuItems; } // 拥有了panCakeMenu的迭代器后,就可删除这个暴露全部内在数据的getMenuItem()方法了 public Iterator createIterator(){ return new PanCakeHouseMenuIterator(menuItems); } }
package javaDesignModede_IteratorMode; import java.util.Iterator; /*餐厅的菜单 * */ public class DinnerMenu{ // 餐厅用的是数组,所以最大长度可定 static final int MAX_ITEMS = 6; int numberOFitems = 0; menuItem[] menuItems; // 构造菜单的方法和煎饼果子相差无几,只是这家有数量限制 public DinnerMenu() { menuItems = new menuItem[MAX_ITEMS]; addItem("蔬菜沙拉", "用沙拉酱和番茄酱", true, 6.5); addItem("酸菜粉丝汤", "", true, 3.00); addItem("韭菜炒肉", "中份", false, 5.3); addItem("热狗", "上面抹层芝士", false, 4.2); } public void addItem(String name, String des, boolean veg, double pri){ menuItem item = new menuItem(name, des, veg, pri); if(numberOFitems >= MAX_ITEMS){ System.out.println("对不起,菜单暂时满了。。。今天就先提供这些吧!"); }else{ menuItems[numberOFitems] = item; numberOFitems++; } } public menuItem[] getMenuItems(){ return menuItems; } // 现在我们拥有了餐厅的迭代器,就不需要getMenuItems() 因为它会暴露我们内在的信息,就相当于把整个数据暴露出来,而迭代器就是一种类似于指针的东西,很好的保护了内在的数据 // 所以我们现在只需要在菜单上增加一个方法来创建这个迭代器给客户 public Iterator createIterator(){ return new DinnerMenuIterator(menuItems); } }
没有迭代器的普通服务员。。。不用维护扩展,并且容易暴露内部信息
package javaDesignModede_IteratorMode; import java.util.ArrayList; import java.util.Iterator; /*两家店已经合并了,现在你需要做的就是创建一个女招待,来应对顾客的需要打印一个定值的菜单,甚至告诉你这个菜单是不是素食 * 而无需询问厨师 * * 要实现的 * printMenu() 打印菜单的每一项 * printPanCakeMenu() 打印煎饼果子的每一项 * printDinnerMenu() 打印餐厅的每一项 * printVegetarianMenu() 打印菜单里所有的素食项 * isItemVegetarian(name) 判断是否是素食 * */ public class Waitress { // 普通版本的女招待 ArrayList<menuItem> forPanCakeList; menuItem[] forDinnerArray; PanCakeHouseMenu panCakeHouseMenu =new PanCakeHouseMenu(); DinnerMenu dinnerMenu =new DinnerMenu(); public Waitress() { this.forPanCakeList = panCakeHouseMenu.getMenuItems(); this.forDinnerArray = dinnerMenu.getMenuItems(); } // 现在得到PanCake菜单项展示出来 public void printPanCakeMenu(){ for (menuItem item : forPanCakeList) { System.out.println(item.toString()); } } public void printDinnerMenu(){ for(int i = 0; i<forDinnerArray.length; ++i){ System.out.println(forDinnerArray[i].toString()); } } // 现在是两家用了不同的方式来存菜单,就需要两张不同的遍历方式,若是第三家也用不同的方式存菜单,岂不是又要遍历一次? // 这样的女招待很难维护,不易扩展...所以我们选择了进阶版的女招待 }
可以发现,上面的女招待也是很累,每入驻一家店,就要从新编写一个遍历的方式,不如就让这些遍历的方式统一实现一个接口,然后运用多态的方式,来再多家
都无所谓~无所谓。。。
现在就是送“胡利”的时间了。。。买一送一,买迭代器,送创建迭代器方法
package javaDesignModede_IteratorMode; import java.util.ArrayList; import java.util.Iterator; public class PanCakeHouseMenuIterator implements Iterator{ // 首先选择迭代的类型 ArrayList<menuItem> panCakeList; // 以及迭代器指向的位置记录 int index = 0; // 然后再对构造方法进行输入具体的迭代区域 public PanCakeHouseMenuIterator(ArrayList<menuItem> list) { this.panCakeList = list; } // 之后再覆盖相应的方法实现迭代 public boolean hasNext() { if(index >= panCakeList.size() || panCakeList.get(index) == null){ return false; }else{ return true; } } public Object next() { menuItem item = (menuItem)panCakeList.get(index); index ++; return item; } }
package javaDesignModede_IteratorMode; /* 现在我们需要一个迭代器来为餐厅的菜单服务 -- 其实就是指针的应用 * */ import java.util.Iterator; public class DinnerMenuIterator implements Iterator{ // 要实现一个迭代器,首先要定义迭代的内容 menuItem[] items; // 然后是迭代器的位置变化需要一个指示器 int position = 0; // 构造器需要传入一个该迭代器具体指向的菜单项作为参数 public DinnerMenuIterator() { } public DinnerMenuIterator(menuItem[] items){ this.items = items; } // 然后覆盖接口的方法 // hasNext() 是查看是否已经遍历完所有的元素,若不是就返回true public boolean hasNext() { if(position >= items.length || items[position] == null){ return false; }else{ return true; } } // 返回下一个元素,并递增其位置 public Object next() { menuItem item = items[position]; position ++; return item; } }
然后方法其实在上面的店里面的菜单已经出现了 createIterator();
拥有了迭代器的服务员,进阶版
package javaDesignModede_IteratorMode; import java.util.Iterator; /*两家店已经合并了,现在你需要做的就是创建一个女招待,来应对顾客的需要打印一个定值的菜单,甚至告诉你这个菜单是不是素食 * 而无需询问厨师 * * 要实现的 * printMenu() 打印菜单的每一项 * printPanCakeMenu() 打印煎饼果子的每一项 * printDinnerMenu() 打印餐厅的每一项 * printVegetarianMenu() 打印菜单里所有的素食项 * isItemVegetarian(name) 判断是否是素食 * */ public class StrongerWaitress { // 进阶版的女招待--会用迭代器的女招待 PanCakeHouseMenu panCakeHouseMenu = new PanCakeHouseMenu(); DinnerMenu dinnerMenu = new DinnerMenu(); public StrongerWaitress(PanCakeHouseMenu p, DinnerMenu d) { this.panCakeHouseMenu = p; this.dinnerMenu = d; } // 打印每一项 --用通用接口实现多态 private void printMenu(Iterator iterator){ while(iterator.hasNext()){ menuItem item = (menuItem)iterator.next(); System.out.println(item.toString()); } } //下面这个方法为每一个菜单创建一个迭代器 public void printMenu(){ Iterator dinnerIterator = dinnerMenu.createIterator(); Iterator panIterator = panCakeHouseMenu.createIterator(); // 调用重载的printMenu来输出菜单 printMenu(dinnerIterator); printMenu(panIterator); } }
所以总结了一下我们程序员做的结果,就是减轻了女招待的工作,嗯,这个很重要,外加不易暴露店里面的内部信息。。。并且易维护和扩展。。。