因为这系列篇幅较长,所以在这里也不进行任何铺垫,直奔主题去啦。
利用组合设计菜单
我们要如何在菜单上应用组合模式呢?一开始,我们需要创建一个组件接口来作为菜单和菜单项的共同接口,让我们能够用统一的做法来处理菜单和菜单项。换句话说,我们可以针对菜单或菜单项调用相同的方法。
让我们从头来看看如何让菜单能够符合组合模式的结构:
实现菜单组件
好了,我们开始编写菜单组件的抽象类;请记住,菜单组件的角色是为叶节点和组合节点提供一个共同的接口。
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 createIterator(); public void print() { throw new UnsupportedOperationException(); }}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 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 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()); }}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 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 iterator = null; ArrayList menuComponents = new ArrayList(); 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 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("---------------------"); }}class Menu extends MenuComponent {
Iterator iterator = null;
ArrayList menuComponents = new ArrayList();
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 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 iterator = menuComponents.iterator(); while (iterator.hasNext()) { MenuComponent menuComponent = iterator.next(); menuComponent.print(); }}
System.out.print("\n" + getName());
System.out.println(", " + getDescription());
System.out.println("---------------------");
Iterator 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(); }}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();
}
}
结果这里就不附上了,请大家自行去跑代码实现吧。相信你们又对组合模式也已经有了一个大概了吧。下一篇,还有更犀利的,组合迭代器等着我们。小编马上回去搞起来,安排上。
爱生活,爱学习,爱感悟,爱挨踢