设计模式之迭代器与组合模式(四)
程序员文章站
2022-10-08 21:35:04
因为这系列篇幅较长,所以在这里也不进行任何铺垫,直奔主题去啦。 利用组合设计菜单 我们要如何在菜单上应用组合模式呢?一开始,我们需要创建一个组件接口来作为菜单和菜单项的共同接口,让我们能够用统一的做法来处理菜单和菜单项。换句话说,我们可以针对菜单或菜单项调用相同的方法。 让我们从头来看看如何让菜单能 ......
因为这系列篇幅较长,所以在这里也不进行任何铺垫,直奔主题去啦。
利用组合设计菜单
我们要如何在菜单上应用组合模式呢?一开始,我们需要创建一个组件接口来作为菜单和菜单项的共同接口,让我们能够用统一的做法来处理菜单和菜单项。换句话说,我们可以针对菜单或菜单项调用相同的方法。
让我们从头来看看如何让菜单能够符合组合模式的结构:
实现菜单组件
好了,我们开始编写菜单组件的抽象类;请记住,菜单组件的角色是为叶节点和组合节点提供一个共同的接口。
public abstract class menucomponent { public void add(menucomponent menucomponent) { throw new unsupportedoperationexception(); } public void remove(menucomponent menucomponent) { throw new unsupportedoperationexception(); } public menucomponent getchild(int i) { throw new unsupportedoperationexception(); } public string getname() { throw new unsupportedoperationexception(); } public string getdescription() { throw new unsupportedoperationexception(); } public double getprice() { throw new unsupportedoperationexception(); } public boolean isvegetarian() { throw new unsupportedoperationexception(); } public abstract iterator<menucomponent> createiterator(); public void print() { throw new unsupportedoperationexception(); } }
让我们来看菜单类。别忘了,这是组合类图里的叶类,它实现组合内元素的行为。
public class menuitem extends menucomponent { 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 double getprice() { return price; } public boolean isvegetarian() { return vegetarian; } public iterator<menucomponent> createiterator() { return new nulliterator(); } public void print() { system.out.print(" " + getname()); if (isvegetarian()) { system.out.print("(v)"); } system.out.println(", " + getprice()); system.out.println(" -- " + getdescription()); } }
我们已经有了菜单项,还需要组合类,这就是我们叫做菜单的。别忘了,此组合类可以持有菜单项或其他菜单。
public class menu extends menucomponent { iterator<menucomponent> iterator = null; arraylist<menucomponent> menucomponents = new arraylist<menucomponent>(); string name; string description; public menu(string name, string description) { this.name = name; this.description = description; } public void add(menucomponent menucomponent) { menucomponents.add(menucomponent); } public void remove(menucomponent menucomponent) { menucomponents.remove(menucomponent); } public menucomponent getchild(int i) { return menucomponents.get(i); } public string getname() { return name; } public string getdescription() { return description; } public iterator<menucomponent> createiterator() { if (iterator == null) { iterator = new compositeiterator(menucomponents.iterator()); } return iterator; } public void print() { system.out.print("\n" + getname()); system.out.println(", " + getdescription()); system.out.println("---------------------"); } }
因为菜单是一个组合,包含了菜单项和其他的菜单,所以它的print()应该打印出它所包含的一切。如果它不这么做,我们就必须遍历整个组合的每个节点,然后将每一项打印出来。这么一来,也就失去了使用组合结构的意义。
所以,print还得进行优化,如下:
public void print() { system.out.print("\n" + getname()); system.out.println(", " + getdescription()); system.out.println("---------------------"); iterator<menucomponent> iterator = menucomponents.iterator(); while (iterator.hasnext()) { menucomponent menucomponent = iterator.next(); menucomponent.print(); } }
看到上面了没,我们用了迭代器。用它遍历所有菜单组件,遍历过程中,可能遇到其他菜单,或者是遇到菜单项。由于菜单和菜单项都实现了print,那我们只要调用print即可。
开始测试数据之前,我们了解一下,在运行时菜单组合是什么样的:
开始运行我们的测试程序啦:
public class menutestdrive { public static void main(string args[]) { menucomponent pancakehousemenu = new menu("pancake house menu", "breakfast"); menucomponent dinermenu = new menu("diner menu", "lunch"); menucomponent cafemenu = new menu("cafe menu", "dinner"); menucomponent dessertmenu = new menu("dessert menu", "dessert of course!"); menucomponent allmenus = new menu("all menus", "all menus combined"); allmenus.add(pancakehousemenu); allmenus.add(dinermenu); allmenus.add(cafemenu); pancakehousemenu.add(new menuitem( "k&b's pancake breakfast", "pancakes with scrambled eggs, and toast", true, 2.99)); pancakehousemenu.add(new menuitem( "regular pancake breakfast", "pancakes with fried eggs, sausage", false, 2.99)); pancakehousemenu.add(new menuitem( "blueberry pancakes", "pancakes made with fresh blueberries, and blueberry syrup", true, 3.49)); pancakehousemenu.add(new menuitem( "waffles", "waffles, with your choice of blueberries or strawberries", true, 3.59)); dinermenu.add(new menuitem( "vegetarian blt", "(fakin') bacon with lettuce & tomato on whole wheat", true, 2.99)); dinermenu.add(new menuitem( "blt", "bacon with lettuce & tomato on whole wheat", false, 2.99)); dinermenu.add(new menuitem( "soup of the day", "a bowl of the soup of the day, with a side of potato salad", false, 3.29)); dinermenu.add(new menuitem( "hotdog", "a hot dog, with saurkraut, relish, onions, topped with cheese", false, 3.05)); dinermenu.add(new menuitem( "steamed veggies and brown rice", "a medly of steamed vegetables over brown rice", true, 3.99)); dinermenu.add(new menuitem( "pasta", "spaghetti with marinara sauce, and a slice of sourdough bread", true, 3.89)); dinermenu.add(dessertmenu); dessertmenu.add(new menuitem( "apple pie", "apple pie with a flakey crust, topped with vanilla icecream", true, 1.59)); dessertmenu.add(new menuitem( "cheesecake", "creamy new york cheesecake, with a chocolate graham crust", true, 1.99)); dessertmenu.add(new menuitem( "sorbet", "a scoop of raspberry and a scoop of lime", true, 1.89)); cafemenu.add(new menuitem( "veggie burger and air fries", "veggie burger on a whole wheat bun, lettuce, tomato, and fries", true, 3.99)); cafemenu.add(new menuitem( "soup of the day", "a cup of the soup of the day, with a side salad", false, 3.69)); cafemenu.add(new menuitem( "burrito", "a large burrito, with whole pinto beans, salsa, guacamole", true, 4.29)); waitress waitress = new waitress(allmenus); waitress.printvegetarianmenu(); } }
结果这里就不附上了,请大家自行去跑代码实现吧。相信你们又对组合模式也已经有了一个大概了吧。下一篇,还有更犀利的,组合迭代器等着我们。小编马上回去搞起来,安排上。
上一篇: 利用递归实现数组的扁平化