第十二章 组合模式

1.1 引言

餐厅都有自己的一份菜单,而菜单由菜单项组成,每个菜单项描述菜名、菜价和描述等信息。

而在一份菜单中,可能包含子菜单,例如:餐厅菜单除了包含菜名,还包含一份甜品子菜单。

菜单结构如下图所示。

在这样的场景下,当需要遍历每一菜单项时,应如何组织和管理数据呢?

组合模式可以解决此场景下的问题,使系统更具灵活性和弹性。

1.2 组合模式

组合模式:允许将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及组合。

可以忽略对象组合和个别对象之间的差异。

组合模式的类图如下图所示。

从图中可以看出,组件分为两种,一种是叶子节点、一种是组合,而组合又包含组件,由此形成树形结构。

1.3 利用组合模式设计菜单

利用组合模式设计菜单的类图如图所示。

定义了菜单抽象组件接口,供菜单项和菜单共同使用:

package headfirst.designpatterns.composite;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 void print(){throw new UnsupportedOperationException();}
}

定义菜单 Menu,其继承了 MenuComponent 接口:

package headfirst.designpatterns.composite;import java.util.ArrayList;
import java.util.Iterator;public class Menu extends MenuComponent{ArrayList<MenuComponent> menuComponents = new ArrayList<MenuComponent>();String name;String description;public Menu(String name, String description) {this.name = name;this.description = description;}@Overridepublic void add(MenuComponent menuComponent){menuComponents.add(menuComponent);}@Overridepublic void remove(MenuComponent menuComponent){menuComponents.remove(menuComponent);}@Overridepublic MenuComponent getChild(int i) {return (MenuComponent) menuComponents.get(i);}@Overridepublic String getName() {return name;}@Overridepublic String getDescription() {return description;}@Overridepublic void print(){System.out.println("\n" + getName());System.out.println(", " + getDescription());System.out.println("---------------------");// 由于菜单可能包含子菜单,因此,需要迭代打印子菜单的菜单项。Iterator<MenuComponent> iterator = menuComponents.iterator();while (iterator.hasNext()){MenuComponent menuComponent = (MenuComponent) iterator.next();menuComponent.print();}}}

定义了菜单 MenuItem 实现了 MenuComponent 接口:

package headfirst.designpatterns.composite;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;}@Overridepublic String getName() {return name;}@Overridepublic String getDescription() {return description;}@Overridepublic boolean isVegetarian() {return vegetarian;}@Overridepublic double getPrice() {return price;}// 没有子菜单,只需打印当前菜单项信息即可。public void print(){System.out.println(" "+getName());if (isVegetarian()){System.out.println("(v)");}System.out.println(","+getPrice());System.out.println("    --  "+ getDescription());}
}

再定义客户代码 Waitress:

package headfirst.designpatterns.composite;public class Waitress {MenuComponent allMenus;public Waitress(MenuComponent allMenus) {this.allMenus = allMenus;}public void printMenu(){allMenus.print();}
}

测试:

package headfirst.designpatterns.composite;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 coffeeMenu = new Menu("COFFEE MENU", "Stuff to go with your afternoon coffee");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("Hot Dog","A hot dog, with saurkraut, relish, onions, topped with cheese",false,3.05));dinerMenu.add(new MenuItem("Steamed Veggies and Brown Rice","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 包含子菜单 dessertMenudinerMenu.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));// cafeMenu 包含子菜单 coffeeMenucafeMenu.add(coffeeMenu);coffeeMenu.add(new MenuItem("Coffee Cake","Crumbly cake topped with cinnamon and walnuts",true,1.59));coffeeMenu.add(new MenuItem("Bagel","Flavors include sesame, poppyseed, cinnamon raisin, pumpkin",false,0.69));coffeeMenu.add(new MenuItem("Biscotti","Three almond or hazelnut biscotti cookies",true,0.89));Waitress waitress = new Waitress(allMenus);waitress.printMenu();}
}

最后,测试结果依次打印出该菜单的所有菜单项。

参考

[1] Freeman E. Head First 设计模式[M] 中国电力出版社.
[2] 菜鸟教程.

设计模式——(12)组合模式相关推荐

  1. 《设计模式》12.组合模式(结构型)

    又称"整体-部分"模式,组合多个对象形成树形结构以表示具有"整体-部分"关系的层次结构,使用户对单个对象和组合对象具有访问一致性. 角色 抽象构件(Compon ...

  2. 每天一个设计模式之组合模式

    作者按:<每天一个设计模式>旨在初步领会设计模式的精髓,目前采用javascript和python两种语言实现.诚然,每种设计模式都有多种实现方式,但此小册只记录最直截了当的实现方式 :) ...

  3. 1、【设计模式】组合模式

    java设计模式之组合模式 [学习难度:★★★☆☆,使用频率:★★★★☆]  树形结构在软件中随处可见,例如操作系统中的目录结构.应用软件中的菜单.办公系统中的公司组织结构等等,如何运用面向对象的方式 ...

  4. 详解设计模式:组合模式

    组合模式(Composite Pattern),又叫部分整体模式,是 GoF 的 23 种设计模式中的一种结构型设计模式. 组合模式 是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组 ...

  5. 结构型设计模式之组合模式

    结构型设计模式之组合模式 组合模式 应用场景 优缺点 主要角色 组合模式结构 分类 透明组合模式 创建抽象根节点 创建树枝节点 创建叶子节点 客户端调用 安全组合模式 创建抽象根节点 创建树枝节点 创 ...

  6. java设计模式之组合模式(树形层级)

    java设计模式之组合模式 学习难度:★★★☆☆,使用频率:★★★★☆]  树形结构在软件中随处可见,例如操作系统中的目录结构.应用软件中的菜单.办公系统中的公司组织结构等等,如何运用面向对象的方式来 ...

  7. Java设计模式之组合模式详解

    文章目录 详解Java设计模式之组合模式 案例引入 组合模式 定义 模式类图结构 相关角色 典型代码 案例分析 类图设计 实例代码 结果分析 JavaJDK中的组合模式 透明组合模式 安全组合模式 组 ...

  8. Java设计模式之组合模式(UML类图分析+代码详解)

    大家好,我是一名在算法之路上不断前进的小小程序猿!体会算法之美,领悟算法的智慧~ 希望各位博友走过路过可以给我点个免费的赞,你们的支持是我不断前进的动力!! 加油吧!未来可期!! 本文将介绍java设 ...

  9. 设计模式之组合模式(Composite)摘录

    23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而 ...

  10. [设计模式] 8 组合模式 Composite

    DP书上给出的定义:将对象组合成树形结构以表示"部分-整体"的层次结构.组合使得用户对单个对象和组合对象的使用具有一致性.注意两个字"树形".这种树形结构在现实 ...

最新文章

  1. 电脑解锁后黑屏有鼠标_笔记本电脑开机黑屏只显示鼠标怎么办?
  2. 5G NGC — PCC 策略与计费控制框架
  3. 一张脑图说清 Nginx 的主流程
  4. 无线传感网3-2.高效率目标物监控
  5. 打响进军元宇宙第一枪!网易云信发布两大元宇宙解决方案
  6. 前端性能优化(PC版)
  7. 用户访问共享计算机没有权限,win7共享没有权限访问 共享文件访问权限的方法...
  8. 贷款被拒,因为你的征信黑洞太多
  9. oracle的环境配置-基本配置
  10. Oracle SQL性能优化的40条军规
  11. 解决 Windows 端口被占用问题
  12. 普通索引和唯一索引,难道还分不清
  13. 开展人力资源数据分析的目的和原因
  14. Linux Bootloader_转载
  15. 索纳塔进入wince系统_23项高级安全驾驶辅助系统环绕 第十代索纳塔新手女司机的福音...
  16. matlab 格式化文件,Matlab 文件格式化/Matlab Source File Formator
  17. 视频教程-WebService实战讲解课程-Java
  18. Maya---2018up4 Python 开发环境配置(win10x64)
  19. 写入clickhouse效率低总结
  20. CVPR 2019 论文汇总(按方向划分,0506 更新中)

热门文章

  1. 【100%通过率】华为OD机试真题 JavaScript 实现【过滤组合字符串】【2023 Q1 | 100分】
  2. android 黑名单 短信拦截
  3. 基于“认知预期”的情境意识预测模型
  4. 进程间通信IPC、LPC、RPC
  5. 《世界大战》《变形金刚》观后感
  6. 苹果Arcade热门游戏推荐
  7. 微信小程序--顶部轮播图
  8. java:JDBC企业级写法,我们学的最终版本,希望对你有用哦
  9. MySQL排他锁使用案例
  10. USGS下载最新LANDSAT8-9数据无反应的原因