问题引入:
在迭代器模式的餐厅菜单例子中,DinnerMenu下还有一个子菜单:甜点菜单。也就是说不仅要支持多个菜单,甚至还要支持菜单中的菜单。
需要考虑到3个问题:
1、需要某种树形结构,可以容纳菜单、子菜单和菜单项。
2、我们需要能在所有菜单项之间游走,包括菜单。
设计方案:
组合模式定义:
引入组合模式:允许你讲对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象和组合对象。
组合模式让我们能用树形方式创建对象的结构,树里面包含了组合以及个别对象。
使用组合结构,我们能把相同的操作应用在组合和个别对象上。换句话说我们可以忽略对象组合和个别对象之间的差别。
组合模式结构图:
利用组合设计菜单:
1、创建一个组件抽象类(MenuComponent)来作为菜单和菜单项的共同接口,让我们能够统一的做法来处理菜单(Menu)和菜单项(MenuItem)。
2、组件抽象类应该包含了菜单和菜单项的所有方法, 菜单和菜单项直接会存在差异的方法,各自实现自己的方法。
MenuComponent:
public abstract class MenuComponent {
protected String name;
protected String description;
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() {
return name;
}
//菜单项和菜单共同拥有一样的行为,直接提供默认的实现,子类直接继承使用。
public String getDescription() {
return description;
}
public double getPrice() {
throw new UnsupportedOperationException();
}
public void print() {
throw new UnsupportedOperationException();
}
}
Menu:
public class Menu extends MenuComponent {
private List<MenuComponent> menuComponentList = new ArrayList<>();
public Menu(String name, String description) {
super.name = name;
super.description = description;
}
@Override
public void add(MenuComponent menuComponent) {
menuComponentList.add(menuComponent);
}
@Override
public void remove(MenuComponent menuComponent) {
menuComponentList.remove(menuComponent);
}
@Override
public MenuComponent getChild(int i) {
return menuComponentList.get(i);
}
@Override
public void print() {
System.out.println("name:" + super.name + ",description:" + super.description);
System.out.println("----------------------------------");
Iterator<MenuComponent> iterator = menuComponentList.iterator();
while (iterator.hasNext()) {
MenuComponent menuComponent = iterator.next();
menuComponent.print();
}
}
}
MenuItem:
public class MenuItem extends MenuComponent {
private double price;
public MenuItem(String name, String description, double price) {
super.name = name;
super.description = description;
this.price = price;
}
@Override
public double getPrice() {
return price;
}
@Override
public void print() {
System.out.println("\tname:" + super.name + ",description:" + super.description + ",price:" + price + "\n");
}
Waitress:
public class Waitress {
private MenuComponent menuComponent;
public Waitress(MenuComponent menuComponent) {
this.menuComponent = menuComponent;
}
public void printMenu(){
menuComponent.print();
}
}
测试代码:
public static void main(String[] args) {
MenuComponent allMenus = new Menu("ALL MENUS","ALL MENUS COMBINED");
MenuComponent dinnerMenu = new Menu("DINNER MENU","DINNER MENU");
MenuComponent cafeMenu = new Menu("cafe menu","cafe menu");
MenuComponent pastaMenuItem = new MenuItem("pasta","pasta",1);
dinnerMenu.add(pastaMenuItem);
allMenus.add(dinnerMenu);
allMenus.add(cafeMenu);
Waitress waitress = new Waitress(allMenus);
waitress.printMenu();
}
组合迭代器:
如果Waiteress需要游走整个菜单,做一些遍历的筛选操作,则需要实现一个组合迭代器,为组合加上一个createIterator()。