迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。
UML类图:
煎饼屋和餐厅合并了!但是有个小问题,虽然两家都同意实现相同的菜单项MenuItem,但是煎饼屋想使用ArrayList储存菜单项,而餐厅则使用数组,为了使女招待能同时访问两家的菜单,我们需要为菜单提供一个统一的访问接口。
先来看菜单项MenuItem,两家店的实现相同
class MenuItem { string name;//名称 string description;//描述 bool vegetarian;//是否是素食 double price;//价格 public MenuItem(string name, string description, bool 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 double getPrice() { return price; } public bool isVegetarian() { return vegetarian; } }
接口Menu,它只定义了一个创建迭代器的方法,实现这个接口的类将提供各自不同的迭代器
interface Menu { Iterator createIterator(); }
煎饼屋菜单,实现了Menu接口
class PancakeHouseMenu : Menu { ArrayList menuItems; public PancakeHouseMenu() { menuItems = new ArrayList(); addItem("K&B's Pancake Breakfast", "Pancakes with scrambled eggs,and toast", true, 2.99); addItem("Regular Pancake Breakfast", "Pancakes with fired eggs,and sausage", false, 2.99); addItem("Blueberry Pancake", "Pancakes with fresh blueberries", true, 3.49); addItem("Waffles", "Waffles,with your choice of blueberries or strawberries", true, 3.59); } public void addItem(string name, string description, bool vegetarian, double price) { MenuItem menuItem = new MenuItem(name, description, vegetarian, price); menuItems.Add(menuItem); } public Iterator createIterator() { return new PancakeHouseIterator(menuItems); } //菜单的其他方法 }
餐厅菜单同样如此
class DinerMenu : Menu { static int Max_ITEMS = 6; int numberOfItems = 0; MenuItem[] menuItems; public DinerMenu() { menuItems = new MenuItem[Max_ITEMS]; addItem("Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99); addItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99); addItem("Soup of the day", "Soup of the day,whit a side of potato salad", false, 3.29); addItem("Hot dog", "A hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05); } public void addItem(string name, string description, bool vegetarian, double price) { MenuItem menuItem = new MenuItem(name, description, vegetarian, price); if (numberOfItems >= Max_ITEMS) { Console.WriteLine("Sorry,menu is full! Can't add item to menu!"); } else { menuItems[numberOfItems] = menuItem; numberOfItems++; } } public MenuItem[] getMenuItems() { return menuItems; } public Iterator createIterator() { return new DinerMenuIterator(menuItems); } //菜单的其他方法 }
接下来看看迭代器,迭代器有一个接口,定义了一些操作
interface Iterator { bool hasNext(); object next(); //更多的方法,例如remove... }
不同的菜单有不同的迭代器,这是煎饼屋的
class PancakeHouseIterator:Iterator { ArrayList items; int position = 0; public PancakeHouseIterator(ArrayList items) { this.items = items; } public object next() { MenuItem menuItem = (MenuItem)items[position]; position++; return menuItem; } public bool hasNext() { if (position>=items.Count) { return false; } else { return true; } } }
这是餐厅的
class DinerMenuIterator:Iterator { MenuItem[] items; int position = 0; public DinerMenuIterator(MenuItem[] items) { this.items = items; } public object next() { MenuItem menuItem = items[position]; position++; return menuItem; } public bool hasNext() { if (position>=items.Length||items[position]==null) { return false; } else { return true; } } }
选择女招待可以方便的用统一的方法操作两家的菜单了
class Waitress { Menu pancakeHouseMenu; Menu dinerMenu; public Waitress(Menu pancake, Menu diner) { this.pancakeHouseMenu = pancake; this.dinerMenu = diner; } public void printMenu() { Iterator pancakeIterator = pancakeHouseMenu.createIterator(); Iterator dinerIterator = dinerMenu.createIterator(); Console.WriteLine("MENU\n----\nBREAKFAT"); printMenu(pancakeIterator); Console.WriteLine("\nLUNCH"); printMenu(dinerIterator); } private void printMenu(Iterator iterator) { while (iterator.hasNext()) { MenuItem menuItem = (MenuItem)iterator.next(); Console.Write(menuItem.getName() + ","); Console.WriteLine(menuItem.getPrice() + "-- "); Console.WriteLine(" "+menuItem.getDescription()); } } }
迭代器的好处是将来如果有新的菜单加入,而它使用了不同的存储方法(例如hashtable),只需要让它实现迭代器接口,而不必修改女招待的操作方式。