Java 设计模式——组合模式

news2024/11/17 11:36:21

目录

  • 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;
    }
    
    @Override
    public void add(MenuComponent menuComponent) {
        menuComponentList.add(menuComponent);
    }
    
    @Override
    public void remove(MenuComponent menuComponent) {
        menuComponentList.remove(menuComponent);
    }
    
    @Override
    public MenuComponent getChild(int index) {
        return menuComponentList.get(index);
    }
    
    @Override
    public 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;
    }
    
    @Override
    public 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.coloradmin.cn/o/1205386.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JDK并发修改异常的一个“BUG“

很多电商公司早期的架构都是基于PHP&#xff0c;所以我身边会有很多很厉害的PHP老哥&#xff0c;但现在都在写Java。昨天看到他在看Java的并发修改异常&#xff0c;正打算秀一波操作&#xff0c;却被他的一个问题难住了&#xff1a; public class ForeachTest {public static …

【EI会议征稿】第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024)

第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024) The 3rd International Academic Conference on Blockchain, Information Technology and Smart Finance 第三届区块链、信息技术与智慧金融国际学术会议 (ICBIS2024) 将于2024年2月23-25日在马来西亚举行。本次会…

Java+Spring Cloud +UniApp +MySql智慧工地综合管理云平台源码

智慧工地围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效. 智慧工地综合管理云平台源码&#xff0c;PC监管端、项目端&#xff1b;APP监管端、项目端、数据可视化大屏端源码&#xf…

计算机毕业设计 基于SpringBoot的失踪人员信息发布与管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

小白看CLIP代码解析

CLIP代码解析 CLIP演示代码&#xff08;以cifar100举例&#xff09;补充11. 为什么选用100*image_feature&#xff1f;2. 为什么使用L2规范点积&#xff0c;而不直接使用点积&#xff1f; cifar100的所有类别model.encode_image >> VisionTransformer补充21. 为什么加入c…

2023亚太杯数学建模C题思路解析

文章目录 0 赛题思路1 竞赛信息2 竞赛时间3 建模常见问题类型3.1 分类问题3.2 优化问题3.3 预测问题3.4 评价问题 4 建模资料5 最后 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 竞赛信息 2023年第十三…

蓝桥杯第三场双周赛(AK)

题目非常典型&#xff0c;很适合学算法。 1111 第 3 场算法双周赛 - 蓝桥云课 双十一的祈祷 题意&#xff1a;求的个位数。 思路&#xff1a;只需要求个位数&#xff0c;因此此题等效于求 ,可用快速幂或者直接看出为1。 #include <bits/stdc.h> using namespace std; …

矩阵置零00

题目链接 矩阵置零 题目描述 注意点 使用 原地 算法 解答思路 思路是需要存储每一行以及每一列是否有0&#xff0c;因为要尽可能使用更少的空间&#xff0c;且新设置为0的格子不能对后续的判断产生影响&#xff0c;所以要在原有矩阵上存储该信息先用两个参数存储第一行和第…

关于反弹Shell个人的一些理解与学习收获

反弹Shell 概念&#xff1a; 反弹shell(reverse shell)&#xff0c;就是控制端(攻击者所有)监听某TCP/UDP端口&#xff0c;被控端发起请求到该端口&#xff0c;并将其命令行的输入输出转发到控制端。reverse shell与telnet&#xff0c;ssh等标准shell对应&#xff0c;本质上是…

Linux 本地zabbix结合内网穿透工具实现安全远程访问浏览器

前言 Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案。能监视各种网络参数&#xff0c;保证服务器系统的安全运营&#xff1b;并提供灵活的通知机制以让系统管理员快速定位/解决存在的各种问题。 本地zabbix web管理界面限制在只能局域…

OpenMMlab导出yolov3模型并用onnxruntime和tensorrt推理

导出onnx文件 直接使用脚本 import torch from mmdet.apis import init_detector, inference_detectorconfig_file ./configs/yolo/yolov3_mobilenetv2_8xb24-ms-416-300e_coco.py checkpoint_file yolov3_mobilenetv2_mstrain-416_300e_coco_20210718_010823-f68a07b3.pth…

计算机网络期末复习-Part5

1、CRC计算 看例题&#xff1a;待发送序列为101110&#xff0c;生成多项式为X31&#xff0c;计算CRC校验码 先在待发送序列末尾添加与生成多项式次数相同的零&#xff0c;在上述例子中&#xff0c;生成多项式是X^3 1&#xff0c;所以需要添加3个零&#xff0c;待发送序列变成…

面试官问 Spring AOP 中两种代理模式的区别?很多面试者被问懵了

面试官问 Spring AOP 中两种代理模式的区别?很多初学者栽了跟头&#xff0c;快来一起学习吧&#xff01; 代理模式是一种结构性设计模式。为对象提供一个替身&#xff0c;以控制对这个对象的访问。即通过代理对象访问目标对象&#xff0c;并允许在将请求提交给对象前后进行一…

11.9乘法器实验总结(流水线,for移位)

for循环乘法器 流水线乘法器 仿真的时候&#xff0c;注意把clk设置一个初始值 分析报告 电路图分析: 比对两种实现方式的RTL级电路图可以发现&#xff0c;for循环的乘法器本质为转为不断的循环累加&#xff0c;故最终电路长度很长&#xff0c;取决于循环&#xff0c;即累加的…

CSS特效008:鼠标悬浮文字跳动动画效果

总第 010 篇文章&#xff0c; 查看专栏目录 本专栏记录的是经常使用的CSS示例与技巧&#xff0c;主要包含CSS布局&#xff0c;CSS特效&#xff0c;CSS花边信息三部分内容。其中CSS布局主要是列出一些常用的CSS布局信息点&#xff0c;CSS特效主要是一些动画示例&#xff0c;CSS花…

VB.NET三层之用户查询窗体

目录 前言: 过程: UI层代码展示: BLL层代码展示: DAL层代码展示: 查询用户效果图:​ 总结: 前言: 想要对用户进行查询&#xff0c;需要用到控件DataGrideView&#xff0c;通过代码的形式将数据库表中的数据显示在DataGrideview控件中&#xff0c;不用对DatGridView控件…

关于财税体制什么是扁平化?三级财政西方的龙骑兵FIBW 10道练习题第五题

目录 关于财税体制什么是扁平化&#xff1f; 三级财政 西方的龙骑兵 FIBW 10道练习题 第五题 关于财税体制什么是扁平化&#xff1f; 在财税领域&#xff0c;"扁平化"&#xff08;Flattening&#xff09;通常指的是简化税收结构&#xff0c;减少税种和税率的层…

深度学习 YOLO 实现车牌识别算法 计算机竞赛

文章目录 0 前言1 课题介绍2 算法简介2.1网络架构 3 数据准备4 模型训练5 实现效果5.1 图片识别效果5.2视频识别效果 6 部分关键代码7 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于yolov5的深度学习车牌识别系统实现 该项目较…

【Liunx】DHCP服务

【Liunx】DHCP服务 DHCP概述A.安装dhcpB.查看配置文件C.修改配置文件 DHCP概述 DHCP(Dynamic Host Configuration Protocol)i动态主机配置协议 DHCP是由Internet工作任务小组设计开发的&#xff0c;专门用于为TCP/IP网络中的计算机自动分配TCP/IP参数的协议。 口使用DHCP服务的…

YOLOv5算法进阶改进(3)— 引入深度可分离卷积C3模块 | 轻量化网络

前言:Hello大家好,我是小哥谈。深度可分离卷积是一种卷积神经网络中的卷积操作,它可以将标准卷积分解为两个较小的卷积操作:深度卷积和逐点卷积。深度卷积是在每个输入通道上分别执行卷积,而逐点卷积是在所有通道上执行卷积。这种分解可以大大减少计算量和参数数量,从而提…