当前位置: 首页 > news >正文

组合模式(Composite Pattern)

使用组合模式(Composite Pattern)是一个更优雅的方式来表示菜单和菜单项。组合模式允许我们将单个对象(如菜单项)和组合对象(如菜单)以相同的方式处理。

解决方案:

  1. 创建组合结构:我们将菜单项和菜单抽象为 MenuComponent,其中菜单项是叶节点,菜单是组合节点。
  2. Menu:可以包含子菜单或菜单项。
  3. MenuItem:代表具体的菜单项。
  4. Waitress:只需处理一个 MenuComponent 对象,并能够遍历所有的菜单和菜单项。

代码实现

1. 创建抽象类 MenuComponent
import java.util.Iterator;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 void print() {throw new UnsupportedOperationException();}public Iterator<MenuComponent> createIterator() {throw new UnsupportedOperationException();}
}
2. 实现 MenuItem 类(叶节点)
public class MenuItem extends MenuComponent {private String name;private String description;private double price;public MenuItem(String name, String description, double price) {this.name = name;this.description = description;this.price = price;}@Overridepublic String getName() {return name;}@Overridepublic String getDescription() {return description;}@Overridepublic double getPrice() {return price;}@Overridepublic void print() {System.out.println("  " + getName() + ": " + getDescription() + " -- ¥" + getPrice());}
}
3. 实现 Menu 类(组合节点)
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class Menu extends MenuComponent {private List<MenuComponent> menuComponents = new ArrayList<>();private String name;private 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 menuComponents.get(i);}@Overridepublic String getName() {return name;}@Overridepublic String getDescription() {return description;}@Overridepublic void print() {System.out.println("\n" + getName() + ": " + getDescription());System.out.println("---------------------");for (MenuComponent menuComponent : menuComponents) {menuComponent.print();}}
}
4. 实现 Waitress
public class Waitress {private MenuComponent allMenus;public Waitress(MenuComponent allMenus) {this.allMenus = allMenus;}public void printMenu() {allMenus.print();}
}
5. 修改测试代码
public class CompositePatternDemo {public static void main(String[] args) {MenuComponent breakfast = new Menu("早餐菜单", "早餐6:00~9:00");MenuComponent lunch = new Menu("午餐菜单", "午餐11:30~14:30");MenuComponent coffeeMenu = new Menu("咖啡菜单", "全天24小时供应");MenuComponent allMenus = new Menu("所有菜单", "所有可使用的菜单");// Add breakfast itemsbreakfast.add(new MenuItem("胡辣汤", "素胡辣汤", 3));breakfast.add(new MenuItem("油条", "按斤称", 2));breakfast.add(new MenuItem("包子", " 莲藕馅", 1.5));// Add lunch itemslunch.add(new MenuItem("茄汁面", "番茄鸡蛋汤面", 8));lunch.add(new MenuItem("蒜汁面", "凉拌面", 7));lunch.add(new MenuItem("臊子面", "羊肉臊子面", 15));// Add coffee itemscoffeeMenu.add(new MenuItem("生椰拿铁", "少冰", 9.99));coffeeMenu.add(new MenuItem("丝绒拿铁", "热饮", 12.99));coffeeMenu.add(new MenuItem("茉莉生椰拿铁", "外卖,少冰,不另外加糖", 16.99));// Combine menusallMenus.add(breakfast);allMenus.add(lunch);allMenus.add(coffeeMenu);// Create waitress and print all menusWaitress waitress = new Waitress(allMenus);waitress.printMenu();}
}

输出结果

所有菜单: 所有可使用的菜单
---------------------早餐菜单: 早餐6:00~9:00
---------------------胡辣汤: 素胡辣汤 -- ¥3.0油条: 按斤称 -- ¥2.0包子:  莲藕馅 -- ¥1.5午餐菜单: 午餐11:30~14:30
---------------------茄汁面: 番茄鸡蛋汤面 -- ¥8.0蒜汁面: 凉拌面 -- ¥7.0臊子面: 羊肉臊子面 -- ¥15.0咖啡菜单: 全天24小时供应
---------------------生椰拿铁: 少冰 -- ¥9.99丝绒拿铁: 热饮 -- ¥12.99茉莉生椰拿铁: 外卖,少冰,不另外加糖 -- ¥16.99

代码解释

  1. MenuComponent 抽象类:定义了菜单和菜单项的通用操作,如 add()remove()getChild() 等。组合对象(Menu)可以包含 MenuComponent,而叶节点(MenuItem)则只处理具体的菜单项。
  2. Menu:可以包含子菜单或菜单项,通过组合来管理多个菜单和子菜单。
  3. MenuItem:叶节点,表示具体的菜单项。
  4. Waitress:只需要处理一个 MenuComponent 对象,无论是叶节点(菜单项)还是组合对象(菜单),都可以通过相同的方式处理并打印。

总结

通过使用组合模式,MenuMenuItem 都被视为 MenuComponentWaitress 只需要一个 MenuComponent 对象即可遍历所有菜单和菜单项。这使得代码非常灵活,易于扩展和维护。

组合模式 (Composite Pattern) 详细解释

1. 组合模式的概念

组合模式允许我们将对象组合成树形结构来表示“部分-整体”的层次结构。它使得客户端能够以一致的方式处理单个对象和组合对象。

在我们的场景中,菜单项(MenuItem)是基本的元素,菜单(Menu)则是组合对象,可以包含其他菜单或菜单项。Waitress 类不需要知道它是在处理菜单还是菜单项,只要调用通用接口即可,这正是组合模式的强大之处。

2. 类结构概述
  • MenuComponent:抽象基类,提供了所有菜单和菜单项的通用操作。它定义了组合和叶节点的接口,如 add()remove()getChild()print() 等操作。

    由于菜单项不需要支持 add()getChild(),而菜单可以包含其他菜单或菜单项,因此这些操作在基类中默认抛出 UnsupportedOperationException,具体的子类可以根据需要覆盖这些方法。

  • Menu:组合对象类,代表一个菜单,可以包含多个 MenuComponent(既可以是子菜单,也可以是菜单项)。它的主要功能是管理子菜单和菜单项,提供添加、删除、获取子组件的操作。

  • MenuItem:叶节点类,代表一个具体的菜单项。它没有子节点,所以不能包含其他 MenuComponent,只能提供自己的基本信息,如名称、描述和价格。

  • Waitress:客户端类,接收一个 MenuComponent,可以遍历和打印所有菜单和菜单项。它对组合和叶节点一视同仁,只调用 print() 方法即可打印出菜单结构。

3. 组合模式的工作原理

通过 MenuComponent 抽象类,Waitress 可以直接使用 MenuComponent 的统一接口,来处理菜单和菜单项的组合结构。组合模式的核心在于它让我们能够像处理单个对象一样,处理整个对象的组合。无论是遍历单个菜单项还是遍历包含多个子菜单的菜单,Waitress 类只需要关心调用通用的 print() 方法。

4. 组合模式的优点
  • 一致性:客户端可以一致地处理叶节点(菜单项)和组合节点(菜单),使得客户端代码变得简洁且灵活。

    在我们实现的 Waitress 类中,它只关心如何遍历和打印 MenuComponent,不需要区分是在处理一个具体的菜单项还是一个包含子菜单的组合对象。

  • 可扩展性:添加新的菜单或菜单项变得非常简单。我们可以在组合中嵌套更多的子菜单,也可以轻松添加新的菜单项,甚至在 Menu 中组合多个 Menu

  • 简化客户端代码:由于客户端只需要处理抽象基类 MenuComponent,不需要分别处理 MenuItemMenu,客户端代码变得非常简洁。这种设计也让系统变得更灵活和可维护。

5. 组合模式中的递归

组合模式的核心在于它是一个递归结构:菜单可以包含子菜单,子菜单又可以包含更多的菜单或菜单项。这种递归结构允许我们通过遍历树形结构来处理所有的菜单项。Menuprint() 方法就是递归调用,遍历所有子菜单和菜单项。

6. 与迭代器模式的对比

虽然组合模式和迭代器模式都能处理多个对象,但它们的目标和使用场景有所不同:

  • 迭代器模式:用于顺序遍历一个集合中的元素,通常用在结构较为扁平的情况下,例如遍历数组或列表中的元素。之前的实现中,我们通过多个 Iterator 来遍历不同菜单,这更适合扁平化的数据结构。

  • 组合模式:适合处理树形结构(如菜单-子菜单-菜单项),在这种情况下,组合模式能够让客户端以统一的方式处理复杂的层次结构。

http://www.lryc.cn/news/433291.html

相关文章:

  • 教你制作一本加密的样本册
  • C语言进阶【1】--字符函数和字符串函数【1】
  • git提交自动带上 Signed-off-by信息
  • 图论(2)
  • ASP.NET Core 入门教学十九 依赖注入ioc
  • omm kill 内存碎片化
  • JS中给元素添加事件监听器的各种方法详解(包含比较和应用场景)
  • Python基本数据类型之复数complex
  • 第六届机器人与智能制造技术国际会议 (ISRIMT 2024)
  • 鸿蒙轻内核M核源码分析系列十九 Musl LibC
  • mysqldump备份恢复数据库
  • 路径规划——RRT算法
  • OPCUA-PLC
  • 在Windows系统上部署PPTist并实现远程访问
  • 【Grafana】Prometheus结合Grafana打造智能监控可视化平台
  • 隐私计算实训营:SplitRec:当拆分学习遇上推荐系统
  • 存在nginx版本信息泄露(请求头中存在nginx中间件版本信息)
  • 在js中观察者模式讲解
  • java常用面试题-基础知识分享
  • iOS——runLoop
  • python: 多模块(.py)中全局变量的导入
  • 0基础学习爬虫系列:Python环境搭建
  • Unity Shader实现简单的各向异性渲染(采用各向异性形式的GGX分布)
  • React开源框架之Refine
  • 【iOS】——渲染原理与离屏渲染
  • 详解CSS
  • Python执行cmd命令
  • 基于激光雷达的无人机相互避障
  • Zookeeper基本原理
  • 【生日视频制作】西游记孙悟空师徒提笔毛笔书法横幅AE模板修改文字软件生成器教程特效素材【AE模板】