因為這系列篇幅較長,所以在這裡也不進行任何鋪墊,直奔主題去啦。 利用組合設計菜單 我們要如何在菜單上應用組合模式呢?一開始,我們需要創建一個組件介面來作為菜單和菜單項的共同介面,讓我們能夠用統一的做法來處理菜單和菜單項。換句話說,我們可以針對菜單或菜單項調用相同的方法。 讓我們從頭來看看如何讓菜單能 ...
因為這系列篇幅較長,所以在這裡也不進行任何鋪墊,直奔主題去啦。
利用組合設計菜單
我們要如何在菜單上應用組合模式呢?一開始,我們需要創建一個組件介面來作為菜單和菜單項的共同介面,讓我們能夠用統一的做法來處理菜單和菜單項。換句話說,我們可以針對菜單或菜單項調用相同的方法。
讓我們從頭來看看如何讓菜單能夠符合組合模式的結構:
實現菜單組件
好了,我們開始編寫菜單組件的抽象類;請記住,菜單組件的角色是為葉節點和組合節點提供一個共同的介面。
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();
}
}
結果這裡就不附上了,請大家自行去跑代碼實現吧。相信你們又對組合模式也已經有了一個大概了吧。下一篇,還有更犀利的,組合迭代器等著我們。小編馬上回去搞起來,安排上。