Java组合模式:构建多层次公司组织架构
在现实生活中,常常会遇到用树形结构组织的一些场景,比如国家省市,学校班级,文件目录,分级导航菜单,以及典型的公司组织架构,整个层次结构自顶向下呈现一颗倒置的树。这种树形结构在面向对象的世界中非常适合用组合模式来处理。
一,概述
组合模式(Composite Pattern),又叫做“部分-整体”模式,是一种结构型设计模式,它允许将对象组织成树状结构,以表示“部分-整体”的层次结构。在这种结构中,可以将相同操作应用于部分和整体,从而实现对单个对象和组合对象的一致性处理。怎么理解单个对象和组合对象,比如一颗倒置的节点树,其中的叶子节点就是单个对象,每个分支节点和其下的所有子节点共同构成组合对象。
组合模式一般包含以下角色:
- 抽象构件(Component):为单个对象和组合对象声明公共接口,定义共有的行为或属性,如添加、删除、获取子节点等方法。
- 叶子构件(Leaf):即单个的对象,表示树形结构中没有子节点的对象,实现了抽象构件中的方法。
- 组合构件(Composite):即组合对象,包含一组子对象,同时实现了抽象构件中添加、删除、获取子节点等方法。
优点
- 提供统一的操作接口,简化客户端代码:客户端代码可以一致地处理单个对象和组合对象,无需区分它们的类型,使客户端代码更加简洁和统一。
- 提升系统灵活性和可扩展性:可以很方便地通过添加新的组合对象或叶子对象来扩展树形结构,并且可以动态地添加、删除和修改对象。
缺点
- 限制了组合对象的类型:组合模式中的组合对象必须实现相同的接口或继承相同的父类。这可能会限制组合对象的类型,使其无法满足特定的需求。
- 可能导致系统过于一般化:组合模式的使用可能导致系统过于一般化,将特定的操作和行为放在组合模式中可能不太合适。
- 增加了系统的复杂性:引入组合模式会增加系统的复杂性,需要更多的类和接口来表示组合结构,增加了代码的数量和理解难度。
适用场景
- 需要表示“部分-整体”层次结构的情况,如树状结构、目录结构等。
- 希望能够以统一的方式处理单个对象和组合对象时。
- 需要动态地添加、删除和修改对象,希望系统具有良好的扩展性时。
二,模拟公司组织架构
案例分析
接下来我们用组合模式来模拟实现下公司组织架构,使得我们可以动态管理公司人员。如上图所示,所有的叶子节点表示普通员工,是单个的对象。所有的分支节点包括根节点表示领导,每个领导都含有下属员工,总裁的下属就是主管,每个领导及其直接下属就构成组合对象。不管是总裁、主管还是普通员工,他们都是公司的雇员,这就是员工和领导的共性。
代码实现
步骤1:创建抽象构件—Employee接口,表示雇员。
public interface Employee {//添加下属员工void add(Employee e);//移除下属员工void remove(Employee e);//获取所有下属员工List<Employee> getSubordinates();//打印员工信息void info();
}
步骤2:创建叶子构件—Worker类,实现Employee接口,表示最底层的员工。对于的员工的管理操作,提供空实现即可。
public class Worker implements Employee{//员工姓名private String name;public Worker(String name) {this.name = name;}@Overridepublic void add(Employee e) {}@Overridepublic void remove(Employee e) {}@Overridepublic List<Employee> getSubordinates() {return null;}@Overridepublic void info() {System.out.println("员工-"+name);}
}
步骤3:创建组合构件—Leader类,实现Employee接口,表示含有下属的领导。代码中用一个集合表示该领导的下属。
public class Leader implements Employee{//领导姓名private String name;//下属集合private List<Employee> subordinates;public Leader(String name) {this.name = name;this.subordinates= new ArrayList<>();}@Overridepublic void add(Employee e) {subordinates.add(e);}@Overridepublic void remove(Employee e) {subordinates.remove(e);}@Overridepublic List<Employee> getSubordinates() {return subordinates;}@Overridepublic void info() {System.out.println("领导-"+name);for(Employee e:subordinates){e.info();}}
}
步骤4:客户端测试。
public class Client {public static void main(String[] args) {Employee ceo=new Leader("ceo");Employee devLeader=new Leader("devLeader");Employee fatLeader=new Leader("fatLeader");ceo.add(devLeader);ceo.add(fatLeader);Employee devWorker01=new Worker("devWorker01");Employee devWorker02=new Worker("devWorder02");devLeader.add(devWorker01);devLeader.add(devWorker02);Employee fatWorker01=new Worker("fatWorker01");Employee fatWorker02=new Worker("fatWorder02");fatLeader.add(fatWorker01);fatLeader.add(fatWorker02);//打印整个公司架构ceo.info();System.out.println();//打印开发部门架构devLeader.info();System.out.println();//测试部门开除员工fatWorker01后的人员结构fatLeader.remove(fatWorker01);fatLeader.info();}
}
测试结果
三,总结
通过本篇文章的案例学习,可以看出组合模式在处理树状结构场景时,非常有用。在实际项目中,如果遇到需要表示对象的“部分-整体”关系,并希望用户能够忽略组合对象和单个对象之间的差异,可以考虑使用组合模式。它可以简化客户端操作,并提升系统灵活性和扩展性。不过,它也可能增加系统的复杂度和理解难度,我们应该根据实际需求进行权衡。
好了,希望这篇文章对你的学习有所帮助,在此感谢你的阅读,我们下次再见!
相关文章:

Java组合模式:构建多层次公司组织架构
在现实生活中,常常会遇到用树形结构组织的一些场景,比如国家省市,学校班级,文件目录,分级导航菜单,以及典型的公司组织架构,整个层次结构自顶向下呈现一颗倒置的树。这种树形结构在面向对象的世…...

Langchain-ChatGLM:基于本地知识库问答
文章目录 ChatGLM与Langchain简介ChatGLM-6B简介ChatGLM-6B是什么ChatGLM-6B具备的能力ChatGLM-6B具备的应用 Langchain简介Langchain是什么Langchain的核心模块Langchain的应用场景 ChatGLM与Langchain项目介绍知识库问答实现步骤ChatGLM与Langchain项目特点 项目主体结构项目…...
设计模式十 适配器模式
适配器模式 适配器模式是一种结构型设计模式。作用:当接口无法和类匹配到一起工作时,通过适配器将接口变换成可以和类匹配到一起的接口。(注:适配器模式主要解决接口兼容性问题) 适配器的优点与缺点: 优…...

1.6 初探JdbcTemplate操作
一、JdbcTemplate案例演示 1、创建数据库与表 (1)创建数据库 执行命令:CREATE DATABASE simonshop DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; 或者利用菜单方式创建数据库 - simonshop 打开数据库simonshop &#x…...

为什么要用线程池?
线程池是一种管理和复用线程资源的机制,它由一个线程池管理器和一组工作线程组成。线程池管理器负责创建和销毁线程池,以及管理线程池中的工作线程。工作线程则负责执行具体的任务。 线程池的主要作用是管理和复用线程资源,避免了线程的频繁…...

c语言的预处理和编译
预处理 文件包含 当预处理器发现#include指令时,会查看后面的文件名并把文件的内容包含到当前文件中 两种写法 尖括号:引用的是编译器的库路径里面的头文件。 双引号:引用的是程序目录中相对路径中的头文件,如果找不到再去上面…...

网络安全必学 SQL 注入
1.1 .Sql 注入攻击原理 SQL 注入漏洞可以说是在企业运营中会遇到的最具破坏性的漏洞之一,它也是目前被利用得最多的漏洞。要学会如何防御 SQL 注入,首先我们要学习它的原理。 针对 SQL 注入的攻击行为可描述为通过在用户可控参数中注入 SQL 语法&#x…...
Docker基础知识详解
✅作者简介:热爱Java后端开发的一名学习者,大家可以跟我一起讨论各种问题喔。 🍎个人主页:Hhzzy99 🍊个人信条:坚持就是胜利! 💞当前专栏:文章 🥭本文内容&am…...

腾讯、阿里入选首批“双柜台证券”,港股市场迎盛夏升温?
6月5日,香港交易所发布公告,将于6月19日在香港证券市场推出“港币-人民币双柜台模式”,当日确定有21只证券指定为双柜台证券。同时,港交所还表示,在双柜台模式推出前,更多证券或会被接纳并加入双…...
CentOS7 使用Docker 安装MySQL
CentOS7 使用Docker 安装MySQL Docker的相关知识本篇不会再概述,有疑惑的同学请自行查找相关知识。本篇只是介绍如何在CentOS7下使用Docker安装相应的镜像。 可登陆Docker官网 https://docs.docker.com 之后可以跟着官方的步骤进行安装。 clipboard.png 具体安装过…...
注解和反射复习
注解 注解:给程序和人看的,被程序读取,jdk5.0引用 内置注解 override:修饰方法,方法声明和重写父类方法, Deprecated:修饰,不推荐使用 suppressWarnings用来抑制编译时的警告,必须添加一个或多个参数s…...
RocketMQ的demo代码
下面是一个使用Java实现的RocketMQ示例代码,用于发送和消费消息: 首先,您需要下载并安装RocketMQ,并启动NameServer和Broker。 接下来,您可以使用以下示例代码来发送和消费消息: Producer.java文件&…...
C++ 连接、操作postgreSQL(基于libpq库)
C++ 连接postgreSQL(基于libpq库) 1.环境2.数据库操作2.1. c++ 连接数据库2.2. c++ 删除数据库属性表内容2.3. c++ 插入数据库属性表内容2.4 c++ 关闭数据库1.环境 使用libpq库来链接postgresql数据库,主要用到的头文件是这个: #include "libpq-fe.h"2.数据库操…...
Node.js技术简介及其在Web开发中的应用
Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,使得JavaScript能够在服务器端运行。Node.js采用事件驱动、非阻塞I/O模型,能够处理大量并发请求,非常适合处理I/O密集型的应用程序。本文将介绍Node.js的特点、优势以及在Web开发中的应…...
时间序列分析:原理与MATLAB实现
2023年9月数学建模国赛期间提供ABCDE题思路加Matlab代码,专栏链接(赛前一个月恢复源码199,欢迎大家订阅):http://t.csdn.cn/Um9Zd 目录 1. 时间序列分析简介 2. 自回归模型(AR) 2.1. 参数估计 2.2. MATLAB实现...
mysql排序之if(isnull(字段名),0,1),字段名 或者 if(isnull(字段名),1,0),字段名
mysql排序之if(isnull(字段名),0,1),字段名 或者 if(isnull(字段名),1,0),字段名 默认情况下,MySQL将null算作最小值。如果想要手动指定null的顺序,可以这样处理: 将null强制放在最前 //null, null, 1,2,3,4(默认就是这样&#…...

华为OD机试真题 Java 实现【递增字符串】【2023Q1 200分】,附详细解题思路
一、题目描述 定义字符串完全由“A’和B"组成,当然也可以全是"A"或全是"B。如果字符串从前往后都是以字典序排列的,那么我们称之为严格递增字符串。 给出一个字符串5,允许修改字符串中的任意字符,即可以将任何的"A"修改成"B,也可以将…...

合并文件解决HiveServer2内存溢出方案
一、文件过多导致HiveServer2内存溢出 1.1查看表文件个数 desc formatted yanyu.tmp• 表文件数量为6522102 1.2查看表文件信息 hadoop fs -ls warehouse/yanyu.db/tmp• 分区为string 类型的time字段,分了2001个区。 1.3.查看某个分区下的文件个数为10000个 …...

韧性数据安全体系缘起与三个目标 |CEO专栏
今年4月,美创科技在数据安全领域的新探索——“韧性”数据安全防护体系框架正式发布亮相。 为帮您更深入了解“韧性数据安全”,我们特别推出专栏“构建适应性进化的韧性数据安全体系”,CEO柳遵梁亲自执笔,进行系列解读分享。 首期…...
华为OD机试真题 Java 实现【火车进站】【牛客练习题】
一、题目描述 给定一个正整数N代表火车数量,0<N<10,接下来输入火车入站的序列,一共N辆火车,每辆火车以数字1-9编号,火车站只有一个方向进出,同时停靠在火车站的列车中,只有后进站的出站了,先进站的才能出站。 要求输出所有火车出站的方案,以字典序排序输出。 …...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...

华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...