继续修改菜单
在迭代器模式中往菜单中加入了迭代器,但是存在一个问题服务员在打印菜单时,每次增加一份菜单就要修改代码,违反开闭原则:
public void printMenu(){ Iterator pancakeIterator = pancakeHouseMenu.createIterator(); Iterator cafeIterator = cafeMenu.createIterator(); printMenu(pancakeIterator); printMenu(cafeIterator); }
为什么不尝试将所有菜单放入一个集合中?
public class Waitress{ ArrayList menus; // 统一到一个菜单集合中,该菜单集合包含多种菜单 public Waitress(ArrayList menus){ this.menus = menus; } public void printMenu(){ // 在菜单集合上进行遍历 Iterator menuIterator = menus.iterator(); while(menuIterator.hasNext()){ Menu menu = (Menu)menuIterator.next(); printMenu(menu.createIterator()); } } private void printMenu(Iterator iterator){ while(iterator.hasNext()){ MenuItem item = (Menuitem)iterator.next(); // 打印操作,此处省略 } } }
上述方法很好解决了问题,但是此时要在咖啡厅菜单中加入一个甜点菜单,这个甜点菜单是一份单独的菜单,并不是将甜点项(菜单项)添加到咖啡厅菜单中,该如何实现?
组合模式
- 允许将对象组合为树形结构来表现整体/部分层次结构,树中包含了组合以及个别对象(即叶子节点和非叶子节点)
- 组合能让客户通过一致的方式处理个别对象和对象组合(即实现相同的接口)
实现菜单组件
菜单组件可以是某个菜单项(叶子节点),也可以是某个菜单(组合,也就是非叶子节点)
public abstract class MenuComponent{
// 下面方法有些只对菜单项(叶子节点)有意义,有些只对菜单(组合,也就是非叶子节点)有意义,所以默认实现抛出异常
public void add(MenuComponent menuComponent){ // 新增菜单组件
throw new UnsupporteOperationException();
}
public void remove(MenuComponent menuComponent){ // 删除菜单组件
throw new UnsupporteOperationException();
}
public MenuComponent getChild(int i){ // 获取菜单组件
throw new UnsupporteOperationException();
}
// 还有getName、getPrice等方法,此处省略
}
实现菜单项
public class MenuItem extends MenuComponent{
String name;
double price;
public MenuItem(String name, double price){
this.name = name;
this.price = price;
}
// 还有getName、getPrice方法,此处省略
public void print(){
// 打印菜品名称和价格,此处省略
}
}
实现组合菜单
对于组合菜单还可以有多个菜单项(叶子节点)以及其他菜单(即子树)
public class Menu extends MenuComponent{
ArrayList menuComponents = new ArrayList(); // 可以有任意数目的孩子,但是都必须是MenuComponent类型
String name;
String desc;
public MenuItem(String name, String desc){
this.name = name;
this.desc = desc;
}
public void add(MenuComponent menuComponent){
menuComponents.add(menuComponent);
}
public void remove(MenuComponent menuComponent){
menuComponents.remove(menuComponent);
}
public MenuComponent getChild(int i){
return (MenuComponent)menuComponents.get(i);
}
// 还有getName、getDesc方法,此处省略
public void print(){
// 打印菜单名称和描述,此处省略
// 除了菜单本身信息,还要打印出菜单中所有组件的信息(即其他菜单和菜单项)
Iterator iterator = menuComponents.iterator();
while(iterator.hasNext()){
MenuComponent menuComponent = (MenuComponent)iterator.next();
menuComponent.print(); // 递归调用
}
}
}
修改服务员代码
把最顶层的菜单组件(即整个树的根节点)给服务员
public class Waitress{
MenuComponent rootmenu; // 将根节点的交给服务员即可
public Waitress(MenuComponent rootmenu){
this.rootmenu = rootmenu;
}
public void printMenu(){
rootmenu.print();
}
}
测试
public class MenuTest{
public static void main(String[] agrs){
// 定义菜单组件(根节点也是菜单组件)
MenuComponent cafeMenu = new Menu("CAFE MENU", "Dinner");
MenuComponent pancakeHouseMenu = new Menu("PNCAKE HOUSE MENU", "Breakfast");
MenuComponent dessertMenu = new Menu("DESSRET MENU", "Anytime");
MenuComponent rootMenu = new Menu("ALL MENUS", "All menus combined");
// 开始构建树
// 1.添加子树
rootMenu.add(cafeMenu);
rootMenu.add(pancakeHouseMenu);
// 2.往子树中添加叶子节点或其他子树
cafeMenu.add(dessertMenu); // 实现开始的目标:往咖啡厅菜单中添加甜点菜单
cafeMenu.add(new MenuItem("BLACK COFFEE", 25)); // 咖啡厅肯定需要咖啡的
// 把完整菜单给服务员
Waitress waitress = new Waitress(rootMenu);
waitress.printMenu();
}
}
已学模式
模式 | 描述 |
---|---|
适配器模式 | 改变一个或多个接口 |
迭代器模式 | 提供一个方式遍历集合,且无需暴露集合的实现 |
外观模式 | 简化一群类的接口 |
组合模式 | 客户可将对象的集合和个别对象一视同仁 |
观察者模式 | 当某个对象改变时,允许一群对象被通知 |