Head First设计模式(阅读笔记)-11.组合模式
创始人
2024-03-24 17:54:53
0

继续修改菜单

在迭代器模式中往菜单中加入了迭代器,但是存在一个问题服务员在打印菜单时,每次增加一份菜单就要修改代码,违反开闭原则:

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();}
}

已学模式


模式描述
适配器模式改变一个或多个接口
迭代器模式提供一个方式遍历集合,且无需暴露集合的实现
外观模式简化一群类的接口
组合模式客户可将对象的集合和个别对象一视同仁
观察者模式当某个对象改变时,允许一群对象被通知

参考

Head First 设计模式-组合模式

设计模式-组合模式

相关内容

热门资讯

保存时出现了1个错误,导致这篇... 当保存文章时出现错误时,可以通过以下步骤解决问题:查看错误信息:查看错误提示信息可以帮助我们了解具体...
汇川伺服电机位置控制模式参数配... 1. 基本控制参数设置 1)设置位置控制模式   2)绝对值位置线性模...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
表格中数据未显示 当表格中的数据未显示时,可能是由于以下几个原因导致的:HTML代码问题:检查表格的HTML代码是否正...
本地主机上的图像未显示 问题描述:在本地主机上显示图像时,图像未能正常显示。解决方法:以下是一些可能的解决方法,具体取决于问...
表格列调整大小出现问题 问题描述:表格列调整大小出现问题,无法正常调整列宽。解决方法:检查表格的布局方式是否正确。确保表格使...
不一致的条件格式 要解决不一致的条件格式问题,可以按照以下步骤进行:确定条件格式的规则:首先,需要明确条件格式的规则是...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...