组合模式(Composite Pattern)
使用组合模式(Composite Pattern)是一个更优雅的方式来表示菜单和菜单项。组合模式允许我们将单个对象(如菜单项)和组合对象(如菜单)以相同的方式处理。
解决方案:
- 创建组合结构:我们将菜单项和菜单抽象为
MenuComponent,其中菜单项是叶节点,菜单是组合节点。 Menu类:可以包含子菜单或菜单项。MenuItem类:代表具体的菜单项。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
代码解释
MenuComponent抽象类:定义了菜单和菜单项的通用操作,如add()、remove()、getChild()等。组合对象(Menu)可以包含MenuComponent,而叶节点(MenuItem)则只处理具体的菜单项。Menu类:可以包含子菜单或菜单项,通过组合来管理多个菜单和子菜单。MenuItem类:叶节点,表示具体的菜单项。Waitress类:只需要处理一个MenuComponent对象,无论是叶节点(菜单项)还是组合对象(菜单),都可以通过相同的方式处理并打印。
总结
通过使用组合模式,Menu 和 MenuItem 都被视为 MenuComponent,Waitress 只需要一个 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,不需要分别处理MenuItem和Menu,客户端代码变得非常简洁。这种设计也让系统变得更灵活和可维护。
5. 组合模式中的递归
组合模式的核心在于它是一个递归结构:菜单可以包含子菜单,子菜单又可以包含更多的菜单或菜单项。这种递归结构允许我们通过遍历树形结构来处理所有的菜单项。Menu 的 print() 方法就是递归调用,遍历所有子菜单和菜单项。
6. 与迭代器模式的对比
虽然组合模式和迭代器模式都能处理多个对象,但它们的目标和使用场景有所不同:
-
迭代器模式:用于顺序遍历一个集合中的元素,通常用在结构较为扁平的情况下,例如遍历数组或列表中的元素。之前的实现中,我们通过多个
Iterator来遍历不同菜单,这更适合扁平化的数据结构。 -
组合模式:适合处理树形结构(如菜单-子菜单-菜单项),在这种情况下,组合模式能够让客户端以统一的方式处理复杂的层次结构。
相关文章:
组合模式(Composite Pattern)
使用组合模式(Composite Pattern)是一个更优雅的方式来表示菜单和菜单项。组合模式允许我们将单个对象(如菜单项)和组合对象(如菜单)以相同的方式处理。 解决方案: 创建组合结构:我…...
教你制作一本加密的样本册
在这个信息的时代,保护自己的隐私和知识产权变得尤为重要。你有没有想过,如何将自己珍贵的样本资料变成一本只有自己才能查看的加密宝典?今天,我就来教你制作一本加密的样本册 第一步,打开浏览器,搜索FLBOO…...
C语言进阶【1】--字符函数和字符串函数【1】
本章概述 字符分类函数字符转换函数strlen的使用和模拟实现strcpy的使用和模拟实现strcat的使用和模拟实现strcmp的使用和模拟实现彩蛋时刻!!! 字符分类函数 字符: 这个概念,我们在以前的文章中讲过了。我们键盘输入的…...
git提交自动带上 Signed-off-by信息
为了确保在使用 Signed-off-by 签名的同时保留你的提交消息,你需要修改 prepare-commit-msg 钩子脚本,以便它不会丢失原始的提交信息。 增加prepare-commit-msg 钩子以保留提交消息 prepare-commit-msg 钩子的目的是在提交信息文件中插入额外的内容&am…...
图论(2)
一、度 度统计的是一个节点上又多少条边 度出度入度 出度:统计以该节点为起始点箭头指向外面的边的条数 入度:统计箭头指向该节点的边数 度为1的节点为悬挂节点,边为悬挂边 用矩阵计算节点的度 二、握手定理 比如这里第一个集合里面有三…...
ASP.NET Core 入门教学十九 依赖注入ioc
ASP.NET Core内置了对依赖注入(Dependency Injection,简称DI)的支持,这是一种设计模式,用于实现控制反转(Inversion of Control,简称IoC),从而使得应用程序组件之间的耦合…...
omm kill 内存碎片化
内存频繁 OOM(Out of Memory)会导致内存碎片化,并进一步加剧无可用内存分配的问题。碎片化是内存管理中常见的问题,当系统频繁分配和释放内存时,内存空间会被分割成许多小块,虽然内存总量可能足够,但这些小块无法满足较大进程或数据的内存需求,最终导致系统无法找到足够…...
JS中给元素添加事件监听器的各种方法详解(包含比较和应用场景)
JavaScript 中给元素添加事件监听器的各种方法详解 在 JavaScript 中,事件处理是前端开发的一个重要部分。无论是点击按钮、提交表单,还是鼠标悬停,都涉及到事件监听。本文中,我将详细讲解各种给元素添加事件监听器的方法&#x…...
Python基本数据类型之复数complex
来源: “码农不会写诗”公众号 链接:Python基本数据类型之复数complex 文章目录 01 基本概念02 基本运算03 拓展1复数与向量 复数complex Python基本数据之复数(complex)即包含实部和虚部的数字。 01 基本概念 即包含实部和虚部的数字。 在Python中&am…...
第六届机器人与智能制造技术国际会议 (ISRIMT 2024)
目录 会议详情 主题 会议官网 会议详情 第六届机器人与智能制造技术国际研讨会(ISRIMT 2024)计划于2024年9月20-22日在常州举行。会议主要聚焦“机器人”和“智能制造技术”的研究领域,旨在为机器人和智能制造技术领域的专家学者、工程技术…...
鸿蒙轻内核M核源码分析系列十九 Musl LibC
往期知识点记录: 鸿蒙(HarmonyOS)应用层开发(北向)知识点汇总 轻内核M核源码分析系列一 数据结构-双向循环链表 轻内核M核源码分析系列二 数据结构-任务就绪队列 鸿蒙轻内核M核源码分析系列三 数据结构-任务排序链表 轻…...
mysqldump备份恢复数据库
mysqldump程序可以用来备份和恢复数据库 ,默认情况mysqldump会创建drop table, create table,和insert into的sql语句. 语法 > mysqldump [options] db_name [tbl_name ...] > mysqldump [options] --databases db_name ... > mysqldump [options] --all-databases备…...
路径规划——RRT算法
路径规划——RRT算法 算法原理 RRT算法的全称是快速扩展随机树算法(Rapidly Exploring Random Tree),它的思想是选取一个初始点作为根节点,通过随机采样,增加叶子节点的方式,生成一个随机扩展树,当随机树中的叶子节点…...
OPCUA-PLC
下载opcua服务器(有PLC可以直连),UaAnsiCServer下载路径 双击运行如下,Endpoint显示opcua服务路径 opc.tcp://DESKTOP-9SD7K4B:48020 下载opcua客户端(类似编写代码连接操作),UaExpert下载路径 如果连接失败,有一个授权认证,点击同意就行 java代码实现连接opcUA操作 pom.…...
在Windows系统上部署PPTist并实现远程访问
在Windows系统上部署PPTist并实现远程访问 前言PPTist简介本地部署PPTist步骤1:获取PPTist步骤2:安装依赖步骤3:运行PPTist 使用PPTist远程访问PPTist步骤1:安装Cpolar步骤2:配置公网地址步骤3:配置固定公网…...
【Grafana】Prometheus结合Grafana打造智能监控可视化平台
✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…...
隐私计算实训营:SplitRec:当拆分学习遇上推荐系统
拆分学习的概念 拆分学习的核心思想是拆分网络结构。每一个参与方拥有模型结构的一部分,所有参与方的模型合在一起形成一个完整的模型。训练过程中,不同参与方只对本地模型进行正向或者反向传播计算,并将计算结果传递给下一个参与方。多个参…...
存在nginx版本信息泄露(请求头中存在nginx中间件版本信息)
在Nginx的配置文件中,server_tokens指令用于控制Nginx在HTTP响应头中包含的服务器版本信息,默认为true,开启状态。当设置为off时,Nginx将不会在响应头中包含任何服务器版本信息,仅显示“Server: nginx”这一行…...
在js中观察者模式讲解
在JavaScript中,观察者模式(Observer Pattern)是一种设计模式,允许一个对象(被观察者,Subject)维护一个依赖它的对象列表(观察者,Observer),并在它自身状态发生变化时自动通知这些观察者。观察者模式的典型使用场景包括事件系统、数据绑定和实时更新等情况。 一 、…...
java常用面试题-基础知识分享
什么是Java? Java是一种高级编程语言,旨在提供跨平台的解决方案。它是一种面向对象的语言,具有简单、结构化、可移植、可靠、安全等特点。 Java的主要特点是什么? Java的主要特点包括: 简单性:Java的语法…...
SkyWalking 10.2.0 SWCK 配置过程
SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外,K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案,全安装在K8S群集中。 具体可参…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
linux 下常用变更-8
1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行,YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID: YW3…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
