Java 设计模式——组合模式

目录

  • 1.概述
  • 2.结构
  • 3.实现
    • 3.1.抽象构件
    • 3.2.容器构件
    • 3.3.叶子节点
    • 3.4.测试
  • 4.分类
  • 5.使用场景
  • 6.优点

1.概述

在这里插入图片描述

(1)大家对于上面这个图片肯定非常熟悉,上图我们可以看做是一个文件系统,对于这样的结构我们称之为树形结构。在树形结构中可以通过调用某个方法来遍历整个树,当我们找到某个叶子节点后,就可以对叶子节点进行相关的操作。可以将这颗树理解成一个大的容器,容器里面包含很多的成员对象,这些成员对象即可是容器对象也可以是叶子对象。但是由于容器对象和叶子对象在功能上面的区别,使得我们在使用的过程中必须要区分容器对象和叶子对象,但是这样就会给客户带来不必要的麻烦,作为客户而已,它始终希望能够一致的对待容器对象和叶子对象。

(2)组合模式 (Composite Pattern),又名部分整体模式,是一种结构型模式,它用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式创建了对象组的树形结构。

2.结构

组合模式主要包含以下三种角色:

  • 抽象构件 (Component):定义组合中对象的共有方法和属性,并可以提供默认的实现。它可以是抽象类或接口。
  • 容器构件 (Composite):表示组合中的容器节点对象,可以包含其他的子节点。实现了抽象构件的接口,并在容器中存储子节点。
  • 叶子构件 (Leaf):表示组合中的叶子节点对象,它没有子节点。实现了抽象构件的接口。

3.实现

【例】软件菜单:如下图,我们在访问别的一些管理系统时,经常可以看到类似的菜单。一个菜单可以包含菜单项(菜单项是指不再包含其他内容的菜单条目),也可以包含带有其他菜单项的菜单,因此使用组合模式描述菜单就很恰当,我们的需求是针对一个菜单,打印出其包含的所有菜单以及菜单项的名称。

在这里插入图片描述

类图如下:
在这里插入图片描述
具体代码如下:

3.1.抽象构件

MenuComponent.java

/*不管是菜单还是菜单项,都应该继承自统一的接口,这里暂时将这个统一的接口称为菜单组件。菜单组件,属于抽象根节点
*/
public abstract class MenuComponent {//菜单组件的名称protected String name;//菜单组件的层级protected int level;//添加子菜单public void add(MenuComponent menuComponent){throw new UnsupportedOperationException();}//移除子菜单public void remove(MenuComponent menuComponent){throw new UnsupportedOperationException();}//获取指定的子菜单public MenuComponent getChild(int index){throw new UnsupportedOperationException();}//获取菜单或者菜单项的名称public String getName(){return name;}//打印菜名称的方法(包含子菜单和子菜单项)public abstract void print();
}

这里的MenuComponent定义为抽象类,因为有一些共有的属性和行为要在该类中实现,Menu和MenuItem类就可以只覆盖自己感兴趣的方法,而不用搭理不需要或者不感兴趣的方法,举例来说,Menu类可以包含子菜单,因此需要覆盖add()、remove()、getChild()方法,但是MenuItem就不应该有这些方法。这里给出的默认实现是抛出异常,也可以根据自己的需要改写默认实现。

3.2.容器构件

Menu.java

//菜单类,属于树枝节点
public class Menu extends MenuComponent{//菜单可以有多个子菜单或者子菜单项private List<MenuComponent> menuComponentList = new ArrayList<MenuComponent>();//构造方法public Menu(String name,int level){this.name = name;this.level = level;}@Overridepublic void add(MenuComponent menuComponent) {menuComponentList.add(menuComponent);}@Overridepublic void remove(MenuComponent menuComponent) {menuComponentList.remove(menuComponent);}@Overridepublic MenuComponent getChild(int index) {return menuComponentList.get(index);}@Overridepublic void print() {//打印菜单名称for (int i = 0; i < level; i++) {System.out.print("--");}System.out.println(name);//打印子菜单或者子菜单项名称for (MenuComponent component : menuComponentList) {component.print();}}
}

Menu类已经实现了除了getName方法的其他所有方法,因为Menu类具有添加菜单,移除菜单和获取子菜单的功能。

3.3.叶子节点

MenuItem.java

//菜单项类,属于叶子节点
public class MenuItem extends MenuComponent{public MenuItem(String name,int level){this.name = name;this.level = level;}@Overridepublic void print() {for (int i = 0; i < level; i++) {System.out.print("--");}//打印菜单项的名称System.out.println(name);}
}

MenuItem是菜单项,不能再有子菜单,所以添加菜单,移除菜单和获取子菜单的功能并不能实现。

3.4.测试

Client.java

public class Client {public static void main(String[] args) {//创建菜单树MenuComponent menu1 = new Menu("菜单管理", 2);menu1.add(new MenuItem("页面访问", 3));menu1.add(new MenuItem("展开访问", 3));menu1.add(new MenuItem("编辑访问", 3));menu1.add(new MenuItem("删除访问", 3));menu1.add(new MenuItem("新增访问", 3));MenuComponent menu2 = new Menu("权限管理", 2);menu2.add(new MenuItem("页面访问", 3));menu2.add(new MenuItem("提交保存", 3));MenuComponent menu3 = new Menu("角色管理", 2);menu3.add(new MenuItem("页面访问", 3));menu3.add(new MenuItem("新增角色", 3));menu3.add(new MenuItem("修改保存", 3));//创建以及菜单MenuComponent component = new Menu("系统管理", 1);//将二级菜单添加到一级菜单中component.add(menu1);component.add(menu2);component.add(menu3);//打印菜单名称(如果有子菜单则一起打印)component.print();}
}

输出结果如下:

--系统管理
----菜单管理
------页面访问
------展开访问
------编辑访问
------删除访问
------新增访问
----权限管理
------页面访问
------提交保存
----角色管理
------页面访问
------新增角色
------修改保存

4.分类

在使用组合模式时,根据抽象构件类的定义形式,我们可将组合模式分为透明组合模式安全组合模式两种形式:

  • 透明组合模式
    • 透明组合模式中,抽象根节点角色中声明了所有用于管理成员对象的方法,比如在示例中 MenuComponent 声明了 add()remove()getChild() 方法,这样做的好处是确保所有的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。
    • 透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的,叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供 add()、remove() 等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)
  • 安全组合模式:在安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在树枝节点 Menu 类中声明并实现这些方法。安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

5.使用场景

(1)组合模式适合以下场景:

  • 表示部分和整体的层次结构:例如,文件系统中的文件和目录之间的关系、菜单和菜单项之间的关系等,都可以使用组合模式来表示。
  • 递归遍历结构:当需要遍历复杂的树形结构,而不管它的具体层次,可以使用组合模式来递归处理整个结构,从而简化代码实现。
  • 具有共性操作的场景:当一个类或一组类具有一些共性操作,但是这些操作可能应用于单个对象或多个对象的集合时,可以使用组合模式来统一处理这些操作,使得代码更加简洁和易于扩展。

(2)总之,组合模式适用于需要使用树形结构表示对象的场景,能够提供一种优雅的设计和管理方式,提高代码灵活性和可扩展性。

6.优点

(1)组合模式的优点包括:

  • 简化客户端代码:组合模式使得客户端可以一致地对待单个对象和组合对象,无需区分它们的类型,从而简化了客户端的代码逻辑。
  • 灵活性和可扩展性:通过组合模式,可以方便地增加、删除和修改组合中的对象,使得整个树形结构具有很高的灵活性和可扩展性。
  • 递归处理:组合模式通过递归方式处理整个树形结构,使得操作变得简单,具有较好的递归性。

(2)组合模式的缺点包括:

  • 可能引入过多的细节:当树形结构非常复杂时,可能会引入更多的细节和复杂性,增加实现和理解的难度。
  • 不适合所有场景:组合模式更适用于表示"部分-整体"的层次结构,如文件夹包含文件等,对于无需表达层次关系的场景,使用组合模式可能会增加不必要的复杂性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/174754.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

通讯协议学习之路(实践部分):SPI开发实践

通讯协议之路主要分为两部分&#xff0c;第一部分从理论上面讲解各类协议的通讯原理以及通讯格式&#xff0c;第二部分从具体运用上讲解各类通讯协议的具体应用方法。 后续文章会同时发表在个人博客(jason1016.club)、CSDN&#xff1b;视频会发布在bilibili(UID:399951374) 本文…

【MySQL】MySQL中的锁

全局锁 全局锁是对整个数据库实例加锁&#xff0c;整个库处于只读状态。 flush tables with read lock 适用场景 全局锁适用于做全库逻辑备份&#xff0c;但是整个库处于只读状态&#xff0c;在备份期间&#xff0c;所有的更新操作、DDL将会被阻塞&#xff0c;会对业务产生影…

SAP ABAP 主动调用外部系统的REST接口(x-www-form-urlencoded)

如何在SAP ECC中调用外部系统提供的REST接口地址&#xff1f; Postman中使用Body中参数情况&#xff0c;使用链接的情况 x-www-form-urlencoded POST成功调用样例如下&#xff1a; SAP中实现如下&#xff1a; 1. 事务码STRUST,导入对方系统证书 2. 事务码SM59配置destinati…

代码随想录Day45 动态规划13 LeetCode T1143最长公共子序列 T1135 不相交的线 T53最大子数组和

LeetCode T1143 最长公共子序列 题目链接:1143. 最长公共子序列 - 力扣&#xff08;LeetCode&#xff09; 题目思路: 动规五部曲分析 1.确定dp数组的含义 这里dp数组的含义是结尾分别为i-1,j-1的text1和text2的最长公共子序列长度 至于为什么是i-1,j-1我之前已经说过了,这里再…

房产中介租房小程序系统开发搭建:详细指南教你如何构建

随着微信小程序的日益普及&#xff0c;越来越多的企业和个人开始尝试开发自己的小程序。以下是制作一个房地产微信小程序的详细教程&#xff0c;希望对大家有所帮助。 一、注册登录乔拓云平台&#xff0c;进入后台 首先&#xff0c;需要注册并登录乔拓云平台&#xff0c;该平台…

【极客时间-系列教程】Vim 实用技巧必知必会-更多常用命令:应对稍复杂的编辑任务

文章目录 更多常用命令&#xff1a;应对稍复杂的编辑任务光标移动文本修改文本对象选择 更多常用命令&#xff1a;应对稍复杂的编辑任务 几个基本的命令已经了解了&#xff0c;可以操作简单的任务&#xff0c;但一些很复杂的命令&#xff0c;并没有了解到&#xff0c;只知道几…

文件上传 [ACTF2020 新生赛]Upload1

打开题目&#xff0c;发现是一道文件上传题目 随便上传个一句话木马上去 发现网站前端有白名单限制&#xff0c;只能上传含有jpg&#xff0c;png&#xff0c;gif的后缀文件 那我们便传个2.jpg的一句话木马上去&#xff0c;bp抓包 我们改成php文件后缀试试&#xff0c;发现重发…

基于入侵杂草算法优化概率神经网络PNN的分类预测 - 附代码

基于入侵杂草算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于入侵杂草算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于入侵杂草优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神…

将铜互连扩展到2nm的研究

晶体管尺寸在3nm时达到临界点&#xff0c;纳米片FET可能会取代finFET来满足性能、功耗、面积和成本目标。同样&#xff0c;正在评估2nm铜互连的重大架构变化&#xff0c;此举将重新配置向晶体管传输电力的方式。 芯片制造商也可能会在2nm节点开始用钌或钼在一定程度上取代铜。…

【系统安装】ubuntu20.04安装,正经教程,小白安装教程,百分百成功安装

1、安装的前提是有启动盘&#xff0c;这个比较好处理&#xff0c;清华源找到ubuntu20.04.iso镜像文件下载&#xff0c;然后用Rufus来制作启动盘就可以了&#xff0c;需要注意的是目标文件系统需要是UEFI&#xff0c;其他的话就没太多要求了&#xff0c;如果卡在这一步的话&…

Java学习之路 —— 异常、集合

文章目录 1. 异常2. 集合2.1 遍历2.1.1 迭代器2.1.2 增强for循环2.1.3 Lambda 2.2 List2.3 Set2.3.1 HashSet2.3.2 LinkedHashSet2.3.3 TreeSet 2.4 Map 1. 异常 Exception&#xff1a;叫异常&#xff0c;是程序员可以捕捉的。异常又分为了2类&#xff1a; 运行时异常&#x…

Web安全:Vulfocus 靶场搭建.(漏洞集成平台)

Web安全&#xff1a;Vulfocus 靶场搭建.&#xff08;漏洞集成平台&#xff09; Vulfocus 是一个包含了多种漏洞靶场的镜像。每个靶场都有具体的漏洞环境和攻击点。Vulfocus 的靶场包括了 Web 安全漏洞、系统安全漏洞、网络安全漏洞、密码学漏洞等多种类型。通关这个靶场我们可以…