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 设计模式-组合模式

设计模式-组合模式

相关内容

热门资讯

前端-session、jwt 目录:   (1)session (2&#x...
linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
关于测试,我发现了哪些新大陆 关于测试 平常也只是听说过一些关于测试的术语,但并没有使用过测试工具。偶然看到编程老师...
前缀和与对数器与二分法 1. 前缀和 假设有一个数组,我们想大量频繁的去访问L到R这个区间的和,...
nodejs:本地安装nvm实... 一、背景-使用不同版本node的原因 vue3+ts、nuxt3版本,node...
JAVA集合知识整理 Java集合知识整理 HashMap相关 HashMap的底层数据结构:jdk1.8之...
无刷直流电机介绍及单片机控制实... 无刷直流电机介绍及单片机控制实例前言基本概念优势与劣势使用寿命基本结构使用单片机控制实例电子调速器&...
fwdiary(2) dp2 1.传纸条  AcWing 275. 传纸条 - AcWing 走两条路,走一条最大的...
常用的DOS命令 常用的DOS命令 DOS(Disk Operating System,磁...
<C++> 类和对象(下) 1.const成员函数将const修饰的“成员函数”称之为const成员函数,cons...