设计模式——组合模式

news2024/12/24 4:03:14

组合模式

定义

组合模式(Composite Pattern)又称为合成模式、部分-整体模式(Part-Whole),主要用来描述部分与整体的关系。
定义:将对象组合成树形结构以表示“部分-整体”的层次结构,使用户对单个对象和组合对象的使用具有一致性

组合模式的优点、缺点、使用场景

优点

  1. 高层模型调用简单。一棵树形结构中所有节点都一视同仁,高层模型不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码
  2. 节点自由增加
    使用组合模式后,想增加一个树枝节点、叶子节点是简单的,只要找到它的父节点即可,拓展性很强。且符合开闭原则,对以后的维护非常有利

缺点

定义节点时使用的是节点实现类,会与依赖倒置原则冲突,限制了接口的使用范围。例如入口类中各个节点都是定义为实现类的类型

使用场景

  1. 如树形菜单、文件、文件夹管理
  2. 从一个整体中独立出部分模块或功能的场景

UML

在这里插入图片描述

运行结果

输入:root节点
在这里插入图片描述

输入:Branch节点
在这里插入图片描述

输入:Leaf节点
在这里插入图片描述

代码实现

Root根节点的接口、实现、个性

public interface IRoot<R extends RootModel, B extends BranchModel, L extends LeafModel> extends ICorp<R> {
	/**
	 * 总经理添加部门经理
	 *
	 * @param branch 分支节点
	 */
	void add(B branch);

	/**
	 * 总经理添加部门员工
	 *
	 * @param leaf 叶子结点
	 */
	void add(L leaf);

	/**
	 * 部门经理遍历下属
	 *
	 * @return
	 */
	List<Object> getSubordinateInfo();
}

public class Root<R extends RootModel, B extends BranchModel, L extends LeafModel> extends RootModel implements IRoot<R, B, L> {
	/**
	 * 下属列表
	 */
	private final List<Object> subordinateList = new ArrayList<>();

	public Root(String name, String position, double salary) {
		super(name, position, salary);
	}

	@Override
	public R getInfo() {
		return (R) this;
	}

	@Override
	public void add(B branch) {
		subordinateList.add(branch);
	}

	@Override
	public void add(L leaf) {
		subordinateList.add(leaf);
	}

	@Override
	public List<Object> getSubordinateInfo() {
		return subordinateList;
	}

	@Override
	public String toString() {
		return "name: " + this.name + "\t" + "position: " + this.position + "\t" + this.salary;
	}
}

public class RootModel extends Corps {
	public RootModel(String name, String position, double salary) {
		super(name, position, salary);
	}
}

Branch分支节点的接口、实现、个性

public interface IBranch<B extends BranchModel, L extends LeafModel> extends ICorp<B> {
	/**
	 * 添加部门
	 *
	 * @param branch 分支节点
	 */
	void add(B branch);

	/**
	 * 添加部门下的员工
	 *
	 * @param leaf 叶子结点
	 */
	void add(L leaf);

	/**
	 * 部门经理获取下属信息
	 *
	 * @return 下属信息列表
	 */
	List<Object> getSubordinateInfo();
}

public class Branch<B extends BranchModel, L extends LeafModel> extends BranchModel implements IBranch<B, L> {
	/**
	 * 下属列表
	 */
	private final List<Object> subordinateList = new ArrayList<>();

	public Branch(String name, String position, double salary) {
		super(name, position, salary);
	}

	@Override
	public B getInfo() {
		return (B) this;
	}

	@Override
	public void add(B branch) {
		subordinateList.add(branch);
	}

	@Override
	public void add(L leaf) {
		subordinateList.add(leaf);
	}

	@Override
	public List<Object> getSubordinateInfo() {
		return subordinateList;
	}

	@Override
	public String toString() {
		return "name: " + this.name + "\t" + "position: " + this.position + "\t" + this.salary;
	}
}

public class BranchModel extends Corps {
	public BranchModel(String name, String position, double salary) {
		super(name, position, salary);
	}
}

Leaf叶子结点接口、实现、个性

public interface ILeaf<L extends LeafModel> extends ICorp<L> {
}

public class Leaf<L extends LeafModel> extends LeafModel implements ILeaf<L> {

	public Leaf(String name, String position, double salary) {
		super(name, position, salary);
	}

	@Override
	public L getInfo() {
		return (L) this;
	}

	@Override
	public String toString() {
		return "name: " + this.name + "\t" + "position: " + this.position + "\t" + this.salary;
	}
}

public class LeafModel extends Corps {
	public LeafModel(String name, String position, double salary) {
		super(name, position, salary);
	}
}

所有员工的公共信息接口、抽象类

public interface ICorp<T> {
	/**
	 * 获取员工信息
	 *
	 * @return 员工信息
	 */
	T getInfo();
}

public abstract class Corps {
	/**
	 * 名称
	 */
	protected String name;
	/**
	 * 职位
	 */
	protected String position;
	/**
	 * 薪水
	 */
	protected double salary;

	protected Corps(String name, String position, double salary) {
		this.name = name;
		this.position = position;
		this.salary = salary;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPosition() {
		return position;
	}

	public void setPosition(String position) {
		this.position = position;
	}

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}
}

帮助类

public class SubordinateHelper {
	/**
	 * 遍历该节点
	 * 只有Root和Branch节点才有下属,Leaf没有下属
	 *
	 * @param node 节点
	 */
	public static <T extends ICorp<R>, R> void getAllSubordinateInfo(T node) {
		printCurrentInfo(node);
		if (node instanceof BranchModel) {
			IBranch<BranchModel, LeafModel> branch = (IBranch<BranchModel, LeafModel>) node;
			iterateSubordinateList(branch.getSubordinateInfo());
		} else if (node instanceof RootModel) {
			IRoot<RootModel, BranchModel, LeafModel> root = (IRoot<RootModel, BranchModel, LeafModel>) node;
			iterateSubordinateList(root.getSubordinateInfo());
		}
	}

	/**
	 * 遍历下属列表
	 *
	 * @param subordinateList 下属列表
	 */
	private static void iterateSubordinateList(List<Object> subordinateList) {
		for (Object subordinate : subordinateList) {
			// 如果是叶子结点,也就是员工
			if (subordinate instanceof LeafModel) {
				ILeaf<LeafModel> leaf = (ILeaf<LeafModel>) subordinate;
				System.out.println("\t\t" + leaf.getInfo());
			} else if (subordinate instanceof BranchModel) {
				// 如果是分支节点,则递归遍历
				IBranch<BranchModel, LeafModel> branch = (IBranch<BranchModel, LeafModel>) subordinate;
				System.out.println("\t" + branch.getInfo());
				iterateSubordinateList(branch.getSubordinateInfo());
			}
		}
	}

	/**
	 * 打印当前节点的信息
	 *
	 * @param root 当前节点
	 * @param <T>  当前节点的类型,IRoot、IBranch、ILeaf
	 * @param <R>  节点的个性类型,RootModel、BranchModel、LeafModel
	 */
	private static <T extends ICorp<R>, R> void printCurrentInfo(T root) {
		System.out.println(root.getInfo());
	}

}

入口类

public class CompositePatternMain {
	public static void main(String[] args) {
		// 生产一个总经理
		Root<RootModel, BranchModel, LeafModel> root = new Root<>("王总", "总经理", 100000d);
		// 生产个秘书
		Leaf<LeafModel> secretary = new Leaf<>("小蓝", "总经理秘书", 20000);
		// 生产三个部门经理
		Branch<BranchModel, LeafModel> liuBranch = new Branch<>("刘经理", "研发部门经理", 30000);
		Branch<BranchModel, LeafModel> zhangBranch = new Branch<>("张经理", "销售部门经理", 31000);
		Branch<BranchModel, LeafModel> heBranch = new Branch<>("何经理", "财务部门经理", 32000);
		// 生产个研发部门副经理
		Leaf<LeafModel> zhengBranch = new Leaf<>("郑副经理", "研发部门副经理", 20000);
		// 生产几个小组长
		Branch<BranchModel, LeafModel> wuBranch = new Branch<>("吴工", "研发一组组长", 10000);
		Branch<BranchModel, LeafModel> liBranch = new Branch<>("李工", "研发二组组长", 11000);
		Branch<BranchModel, LeafModel> songBranch = new Branch<>("宋工", "销售一组组长", 12000);
		Branch<BranchModel, LeafModel> liangBranch = new Branch<>("梁工", "销售二组组长", 13000);
		Branch<BranchModel, LeafModel> zhouBranch = new Branch<>("周工", "财务一组组长", 14000);
		Branch<BranchModel, LeafModel> zhaoBranch = new Branch<>("赵工", "财务二组组长", 15000);
		// 生产员工
		Leaf<LeafModel> a = new Leaf<>("A", "研发一组人员", 3000);
		Leaf<LeafModel> b = new Leaf<>("B", "研发一组人员", 3000);
		Leaf<LeafModel> c = new Leaf<>("C", "研发一组人员", 3000);
		Leaf<LeafModel> d = new Leaf<>("D", "研发二组人员", 3000);
		Leaf<LeafModel> e = new Leaf<>("E", "研发二组人员", 3000);
		Leaf<LeafModel> f = new Leaf<>("F", "研发二组人员", 3000);
		Leaf<LeafModel> g = new Leaf<>("G", "销售一组人员", 3000);
		Leaf<LeafModel> h = new Leaf<>("H", "销售一组人员", 3000);
		Leaf<LeafModel> i = new Leaf<>("I", "销售二组人员", 3000);
		Leaf<LeafModel> j = new Leaf<>("J", "财务一组人员", 3000);
		Leaf<LeafModel> k = new Leaf<>("K", "财务二组人员", 3000);

		// 总经理管理部门经理
		root.add(liuBranch);
		root.add(zhangBranch);
		root.add(heBranch);
		// 总经理管理秘书
		root.add(secretary);
		// 研发、销售、财务部门组长管理
		liuBranch.add(wuBranch);
		liuBranch.add(liBranch);
		liuBranch.add(zhengBranch);
		zhangBranch.add(songBranch);
		zhangBranch.add(liangBranch);
		heBranch.add(zhouBranch);
		heBranch.add(zhaoBranch);
		// 研发部门员工管理
		wuBranch.add(a);
		wuBranch.add(b);
		wuBranch.add(c);
		liBranch.add(d);
		liBranch.add(e);
		liBranch.add(f);
		// 销售部门员工管理
		songBranch.add(g);
		songBranch.add(h);
		liangBranch.add(i);
		// 财务部门员工管理
		zhouBranch.add(j);
		zhaoBranch.add(k);

		// 遍历节点
		SubordinateHelper.getAllSubordinateInfo(a);
	}
}

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

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

相关文章

【C#】并行编程实战:同步原语(2)

在第4章中讨论了并行编程的潜在问题&#xff0c;其中之一就是同步开销。当将工作分解为多个工作项并由任务处理时&#xff0c;就需要同步每个线程的结果。线程局部存储和分区局部存储&#xff0c;某种程度上可以解决同步问题。但是&#xff0c;当数据共享时&#xff0c;就需要用…

电商项目“商品分类浏览”如何测试?附详细思维导图

电商项目无论是工作中&#xff0c;还是面试中&#xff0c;都是一个高频出现的词。面试官非常热衷提问关于电商项目的问题。例如商品分类怎么测试&#xff1f;购物车怎么测试&#xff1f;订单怎么测试&#xff1f;优惠券怎么测试&#xff1f;支付怎么测试&#xff1f;等等 今天…

【Spring Cloud系列】- Ribbon详解与实战

【Spring Cloud系列】- Ribbon详解与实战 文章目录 【Spring Cloud系列】- Ribbon详解与实战一、什么是Ribbon二、Spring Cloud中Ribbon应用Ribbon使用步骤如下 三、Ribbon负载均衡策略设置3.1 全局策略设置3.2 基于注解的针对单个服务的 Ribbon 负载均衡策略3.2.1 注解方式3.2…

『赠书活动 | 第十五期』《Java核心技术·卷II》

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 『赠书活动 &#xff5c; 第十五期』 本期书籍&#xff1a;《Java核心技术卷II》 公众号赠书&#xff1a;第六期 参与方式&#xff1a;关注公众号&#xff1a;低调而…

折叠屏手机的屏幕,华为Mate X3给出了一份“内外兼修”的解决方案

说起折叠屏手机&#xff0c;屏幕一直都是这个领域的重头戏&#xff0c;很多人都对折叠屏手机有一种刻板印象&#xff0c;那就是脆弱。但是&#xff0c;3月份华为最新推出的Mate X3可以说是非常的亮眼&#xff0c;在内外屏幕、水滴铰链、影像系统等多个核心部件的全方位提升&…

MKPFMSEG字段增强后 关于 BAPI_GOODSMVT_CREATE 的extensionin的增强参数带入。

首先在MKPF 的增强表结构 BAPI_TE_XMKPF 增强字段 如果是行项目上的 BAPI_TE_XMSEG 然后在实际赋值的时候 前面14位数是 10位物料凭证号 4位 年度 CLEAR: ls_extensionin.ls_extensionin-STRUCTURE BAPI_TE_XMKPF.ls_extensionin-valuepart114(50) ls_…

告诉你有哪些音频转换成mp3免费软件

曾经有一个名叫小华的音乐爱好者&#xff0c;他对于收集和欣赏各种类型的音频文件情有独钟。然而&#xff0c;他在构建自己的音乐库时遇到了一个困扰&#xff1a;不同设备和平台支持的音频格式千差万别&#xff0c;这让他无法顺利地播放和分享自己喜爱的音乐。幸运的是&#xf…

GTK列表显示文本和图片

使用GtkTreeView控件显示包含文本和图片的列表&#xff0c;GtkTreeView/GtkListStore或者GtkTreeView/GtkTreeModel使用的是MVC设计理念。 关于MVC: M层: model 数据模型层(处理数据的增删改查) 提供数据 V层: Views 视图层 (数据展示) 渲染数据 C层: controller 控制层(处理业…

【UI框架-uView】Input输入框如何使用前后槽?

【UI框架-uView】Input输入框如何使用前后槽&#xff1f; 官方链接如下&#xff1a;Input输入框 - 前后槽 前槽如下&#xff1a; 后槽如下&#xff1a; 可以看到&#xff0c;前后槽的灵活使用&#xff0c;不仅方便我们的布局&#xff0c;还可以在input中实现复杂的应用。 注意…

Vue 组件化开发

文章目录 前言组件化开发父子组件相互传数据父传子&#xff1a;自定义属性子传父&#xff1a;自定义事件父子组件互传案例 插槽 slot多个插槽 总结组件化开发总结Vue组件的基本组成子组件使用的三个步骤父子组件相互传递数据 前言 提示&#xff1a;这里可以添加本文要记录的大…

jenkins 创建项目的ci

一.创建视图 1.点击加号 选择列表视图 2.输入名称&#xff0c;点击确定 二.创建任务 1.点击到你新建的视图之后&#xff0c;再点击文本中的创建一个新的任务。 2.进入创建页面后首先填写描述 三.选择丢弃旧的构建 保持构建的天数是指&#xff1a;是指保留多少天内的构建 …

【基于FPGA的芯片设计】RISC-V的20条指令CPU设计

实验板卡&#xff1a;xc7a100tlc sg324-2L&#xff0c;共20个开关 实验要求&#xff1a;

【C#】并行编程实战:同步原语(1)

在第4章中讨论了并行编程的潜在问题&#xff0c;其中之一就是同步开销。当将工作分解为多个工作项并由任务处理时&#xff0c;就需要同步每个线程的结果。线程局部存储和分区局部存储&#xff0c;某种程度上可以解决同步问题。但是&#xff0c;当数据共享时&#xff0c;就需要用…

Chrome内建DNS导致的解析错误修复

Index Chrome内建DNSDisable Async DNS resolver Chrome内建DNS 实际上 , Chrome在使用自己的DNS来进行域名的解析 , 这导致有时候一些域名解析会出现错误 , 导致访问速度变慢 , 例如 blog.csdn.net 使用谷歌的 8.8.8.8 dns解析就会 , 解析到香港的ip上去 , 导致访问速度变慢 …

群晖NAS:docker查询注册表失败解决方案 docker安装网心云、mysql等

群晖NAS&#xff1a;docker查询注册表失败解决方案 差不多2023年4月底开始的&#xff0c;docker内不能直接搜索注册表。据说是有人在库里放了一些有意思的东西&#xff0c;被和谐掉了&#xff0c;所以也别指望什么时候能解封。 网上很多案例&#xff0c;都不能用。还有奇葩的…

史上最细接口测试详解,接口测试从0到1实施,一篇打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、接口测试描述定…

【C语言】-- 死循环了怎么办?

#include <stdio.h> int main() {int i 0;int arr[] {1,2,3,4,5,6,7,8,9,10};for(i0; i<12; i){arr[i] 0;printf("hello\n");}return 0; } 阅读上面这个代码&#xff0c;我们会认为这不就是简单的数组访问越界么。那么这段代码就应该会报错&#xff0c;…

macOS Sonoma 14beta 3 (23A5286i)第二个更新「附黑/白苹果镜像下载」

系统镜像下载&#xff1a; 系统介绍 黑果魏叔 7 月12 日消息&#xff0c;苹果今天发布 macOS Sonoma 14.0 Beta 3&#xff08;内部版本号&#xff1a;23A5286i&#xff09;第二个更新。 目前尚不清楚苹果为什么要发布 macOS Sonoma Beta 3 的第二个版本&#xff0c;但它可能…

外包干了2年,我裸辞了...

我25岁&#xff0c;中级测试&#xff0c;外包&#xff0c;薪资13.5k&#xff0c;人在上海。内卷什么的就不说了&#xff0c;而且人在外包那些高级精英年薪大几十的咱也接触不到&#xff0c;就说说外包吧。 假设以我为界限&#xff0c;25岁一线城市13.5k&#xff0c;那22-24大部…

CUDA11.1、cuDNN8.6.0、Tensorrt8.5.3,ubuntu20.04安装过程记录

CUD11.1 下载地址&#xff1a;CUDA Toolkit Archive | NVIDIA Developer 安装&#xff1a; wget https://developer.download.nvidia.com/compute/cuda/11.1.1/local_installers/cuda_11.1.1_455.32.00_linux.run sudo sh cuda_11.1.1_455.32.00_linux.run 对于不是sudo用户&…