设计模式--组合模式

缘起

某日,小明公司最近接到一个办公管理系统的项目,并且在每个城市都有分部。这属于是很常见的OA系统,只要前期将需求分析完善好,中后期开发维护是不难的。

然而,总部公司使用后觉得很OK,想要其他城市的分公司也执行使用。但是现在的问题是,其他分公司的部门和制度没有总公司那么清晰完善。

也许可以一个城市一套代码?但是总公司不乐意了,要求总部、分部等是需要成树状结构的,不可以平行管理。

那么部门Leader想到了一个合适的设计模式–组合模式。

组合模式

组合模式(Composite):将对象组合成树形结构以表示’部门-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

结构图

在这里插入图片描述

Component:作为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为,声明一个接口用于访问和管理Component的子组件

通常使用add和remove增加或删除树枝或树叶的功能

public abstract class Component {
    
    protected String name;

    public Component(String name) {
        this.name = name;
    }
    public abstract void add(Component component);
    public abstract void remove(Component component);
	public abstract void display(int depth);
}
  • Leaf在组合中表示叶节点对象,叶子节点没有子节点,所以add和remove对于Leaf对象来说是没用的,给客户端个提示就行。
public class Leaf extends Component {

    public Leaf(String name) {
        super(name);
    }

    @Override
    public void add(Component component) {
        System.out.println("Cannot add to a leaf");
    }
    @Override
    public void remove(Component component) {
        System.out.println("Cannot remove from a leaf");
    }
    
    // 叶子节点展示职级和名称
    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
    }
}
  • Composite定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关的操作,比如增加add和删除remove
public class Composite extends Component {

    private List<Component> children = new ArrayList<>();

    public Composite(String name) {
        super(name);
    }

    @Override
    public void add(Component component) {
        children.add(component);
    }

    @Override
    public void remove(Component component) {
        children.remove(component);
    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
		// 表层级关系+2
        for (Component item : children) {
            item.display(depth + 2);
        }
    }
}
  • 客户端调用,可以通过Component接口操作组合部件的对象
// 顶级节点
Composite root = new Composite("root");
// 添加两个叶子节点
root.add(new Leaf("Leaf A"));
root.add(new Leaf("Leaf B"));

Composite comp = new Composite("Composite X");
// 加两个叶子节点
comp.add(new Leaf("Leaf A"));
comp.add(new Leaf("Leaf B"));

// 顶级节点加一个枝节点
root.add(comp);

Composite comp2 = new Composite("Composite XY");
// 加两个叶子节点
comp.add(new Leaf("Leaf XYA"));
comp.add(new Leaf("Leaf XYB"));

// 二级节点再加一个枝节点
comp.add(comp2);

// 展示整个架构
root.display(1);

结果

-root
---Leaf A
---Leaf B
---Composite X
-----Leaf A
-----Leaf B
-----Leaf XYA
-----Leaf XYB
-----Composite XY

当发现需求中是体现部分与整体层次的结构时,希望用户可以忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象时,就应该考虑使用组合模式了。

在java开发窗体应用的容器控件Container继承了Component(java自带的),就有add和remove方法,所以它在上面增加控件,如Button、Label、Checkbox等就变成了很自然的事,这就是典型的组合模式的应用。

公司管理系统案例

在这里插入图片描述

公司类:抽象类或接口

public abstract class Company {
    protected String name;

    public Company(String name) {
        this.name = name;
    }
    
    public abstract void add(Company company);  // 增加
    public abstract void remove(Company company); // 删除
    public abstract void display(int depth);    // 展示
    public abstract void lineOfDuty();  // 展示职责
    
}

具体公司类:实现接口、树枝节点

public class ConcreteCompany extends Company {

    protected List<Company> children = new ArrayList<>();
    public ConcreteCompany(String name) {
        super(name);
    }

    @Override
    public void add(Company company) {
        children.add(company);
    }

    @Override
    public void remove(Company company) {
        children.remove(company);
    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);

        for (Company child : children) {
            child.display(depth + 2);
        }
    }

    @Override
    public void lineOfDuty() {
        for (Company child : children) {
            child.lineOfDuty();
        }
    }
}
  • 人力资源部、财务部:叶子节点
// HR
public class HRDept extends Company {
    public HRDept(String name) {
        super(name);
    }

    @Override
    public void add(Company company) {

    }

    @Override
    public void remove(Company company) {

    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
    }

    @Override
    public void lineOfDuty() {
        System.out.println(name+"员工招聘培训");
    }
}
// 财务部
public class FinanceDept extends Company {

    public FinanceDept(String name) {
        super(name);
    }

    @Override
    public void add(Company company) {

    }

    @Override
    public void remove(Company company) {

    }

    @Override
    public void display(int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("-");
        }
        System.out.println(name);
    }

    @Override
    public void lineOfDuty() {
        System.out.println(name + "公司财务收支管理");
    }
}
  • 客户端
// 顶级节点
ConcreteCompany root = new ConcreteCompany("总公司");
root.add(new HRDept("总公司人力资源"));
root.add(new FinanceDept("总公司财务部"));


ConcreteCompany comp = new ConcreteCompany("某分公司");
comp.add(new HRDept("某分公司人力资源"));
comp.add(new FinanceDept("某分公司财务部"));

// 给总公司增加下级部门
root.add(comp);

ConcreteCompany comp2 = new ConcreteCompany("A办事处");
comp2.add(new HRDept("A办事处人力资源"));
comp2.add(new FinanceDept("A办事处财务部"));
comp.add(comp2);

ConcreteCompany comp3 = new ConcreteCompany("B办事处");
comp3.add(new HRDept("B办事处人力资源"));
comp3.add(new FinanceDept("B办事处财务部"));

comp.add(comp3);
System.out.println("结构图");
root.display(1);

System.out.println("职责");
root.lineOfDuty();
结构图
-总公司
---总公司人力资源
---总公司财务部
---某分公司
-----某分公司人力资源
-----某分公司财务部
-----A办事处
-------A办事处人力资源
-------A办事处财务部
-----B办事处
-------B办事处人力资源
-------B办事处财务部
职责
总公司人力资源员工招聘培训
总公司财务部公司财务收支管理
某分公司人力资源员工招聘培训
某分公司财务部公司财务收支管理
A办事处人力资源员工招聘培训
A办事处财务部公司财务收支管理
B办事处人力资源员工招聘培训
B办事处财务部公司财务收支管理

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

softmax回实战

1.数据集 MNIST数据集 (LeCun et al., 1998) 是图像分类中广泛使用的数据集之一&#xff0c;但作为基准数据集过于简单。 我们将使用类似但更复杂的Fashion-MNIST数据集 (Xiao et al., 2017)。 import torch import torchvision from torch.utils import data from torchvisi…

STM32标准库开发—软件I2C读取MPU6050

软件模拟I2C时序 初始化I2C引脚以及时钟 void MyI2C_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_ModeGPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_PinGPIO_Pin_10|GPIO_Pin_11;GPIO_InitStruct.G…

pearcmd文件包含漏洞

1.什么是pearcmd.php pecl是PHP中用于管理扩展而使用的命令行工具&#xff0c;而pear是pecl依赖的类库。在7.3及以前&#xff0c;pecl/pear是默认安装的&#xff1b;在7.4及以后&#xff0c;需要我们在编译PHP的时候指定--with-pear才会安装 不过&#xff0c;在Docker任意版本…

(菜鸟自学)Metasploit漏洞利用——ms08-067

&#xff08;菜鸟自学&#xff09;漏洞利用——ms08-067 漏洞简介利用nmapMSF软件对XP sp3系统进行渗透攻击设置exploit模块参数RHOSTRPORTSMBPIPEExploit Target 设置有效载荷查找可兼容的有效载荷 渗透测试VNC 漏洞简介 MS08-067 是指微软于2008年发布的一个安全漏洞&#x…

重学Java 10 面向对象

正是风雨欲来的时候&#xff0c;火却越烧越旺了 ——24.1.20 重点 1.为何使用面向对象思想编程 2.如何使用面向对象思想编程 3.何时使用面向对象思想编程 4.利用代码去描述世间万物的分类 5.在一个类中访问另外一个类中的成员 -> new对象 6.成员变量和局部变量的区别 一…

利用HTML+CSS+JS打造炫酷时钟网页的完整指南

引言 在现代Web开发中&#xff0c;制作一个引人注目的时钟网页是一种常见而令人愉悦的体验。本文将介绍如何使用HTML、CSS和JavaScript来创建一个炫酷的时钟网页&#xff0c;通过这个项目&#xff0c;你将学到如何结合这三种前端技术&#xff0c;制作一个动态且美观的时钟效果…

接口测试 02 -- JMeter入门到实战

前言 JM eter毕竟是做压测的工具&#xff0c;自动化这块还是有缺陷。 如果公司做一些简单的接口自动化&#xff0c;可以考虑使用JMeter快速完成&#xff0c;如果想做完善的接口自动化体系&#xff0c;建议还是基于Python来做。 为什么学习接口测试要先从JMeter开始&#xff1f;…

C语言数据结构——顺序表

&#xff08;图片由AI生成&#xff09; 0.前言 在程序设计的世界里&#xff0c;数据结构是非常重要的基础概念。本文将专注于C语言中的一种基本数据结构——顺序表。我们将从数据结构的基本概念讲起&#xff0c;逐步深入到顺序表的内部结构、分类&#xff0c;最后通过一个实…

Unity常用的优化技巧集锦

Unity性能优化是面试的时候经常被问道的一些内容&#xff0c;今天给大家分享一些常用的Unity的优化技巧和思路&#xff0c;方便大家遇到问题时候参考与学习。 对啦&#xff01;这里有个游戏开发交流小组里面聚集了一帮热爱学习游戏的零基础小白&#xff0c;也有一些正在从事游…

电脑pdf如何转换成word格式?用它实现pdf文件一键转换

pdf转word格式可以用于提取和重用pdf文档中的内容&#xff0c;有时候&#xff0c;我们可能需要引用或引用pdf文档中的一些段落、表格或数据&#xff0c;通过将pdf转换为可编辑的Word文档&#xff0c;可以轻松地复制和粘贴所需内容&#xff0c;节省我们的时间&#xff0c;那么如…

【守护工地安全】YOLOv8实现安全帽检测

学习《OpenCV应用开发&#xff1a;入门、进阶与工程化实践》一书 做真正的OpenCV开发者&#xff0c;从入门到入职&#xff0c;一步到位&#xff01; 数据集 该图像数据集包含8000张图像&#xff0c;两个类别分别是安全帽与人、以其中200多张图像为验证集&#xff0c;其余为训…

谁说知识库都是英文的 今天就来一个中文版的

1.安装 1.1创建目录 mkdir -p /opt/trilium-cn cd /opt/trilium-cn 1.2.编写docker-compose.yml文件 version: 3 services:trilium-cn:image: nriver/trilium-cnrestart: alwaysports:- "10012:8080"volumes:# 把同文件夹下的 trilium-data 目录映射到容器内- /opt…

基于JavaWeb+SSM+Vue基于微信小程序生鲜云订单零售系统的设计和实现

基于JavaWebSSMVue基于微信小程序生鲜云订单零售系统的设计和实现 滑到文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 滑到文末获取源码 Lun文目录 目录 1系统概述 1 1.1 研究背景 1 1.2研究目的 1 1.3系统设计…

6.4.4释放音频

6.4.4释放音频 许多Flash动画里的音乐或歌曲非常好听&#xff0c;能不能在没有源文件的情况下把里面的声音文件取出来呢&#xff1f;利用Swf2VideoConverter2可以轻松做到这一点。 1&#xff0e;单击“添加”按钮&#xff0c;在弹出的下拉菜单中选择“添加文件”&#xff0c;…

java小项目:简单的收入明细记事本,超级简单(不涉及数据库,通过字符串来记录)

一、效果 二、代码 2.1 Acount类 package com.demo1;public class Acount {public static void main(String[] args) {String details "收支\t账户金额\t收支金额\t说 明\n"; //通过字符串来记录收入明细int balance 10000;boolean loopFlag true;//控制循…

iOS中的视频播放

引言 在数字时代&#xff0c;视频已成为我们日常沟通和娱乐不可或缺的一部分。从简短的社交媒体剪辑到全长电影&#xff0c;我们对流畅、高质量视频播放的需求从未如此强烈。对于开发者来说&#xff0c;为iOS用户提供无瑕疵的视频体验是一项挑战&#xff0c;也是一种艺术。本篇…

数据结构之list类

前言 list是列表类。从list 类开始&#xff0c;我们就要接触独属于 Python 的数据类型了。Python 简单、易用&#xff0c;很大一部分原因就是它对基础数据类型的设计各具特色又相辅相成。 话不多说&#xff0c;让我们开始学习第一个 Python 数据类型一list。 1. list的赋值 输…

手把手教你使用 VS Code 运行和调试 Python 程序

本文以 Ubuntu 系统为例&#xff0c;介绍如何在 VS Code 上配置 Python 的编程环境&#xff0c;并把 Python 程序运行、调试起来。由于 Python 是解释型语言&#xff0c;并且 VS Code 中提供了内置的调试器可用于调试 Python 代码&#xff0c;因此配置和操作流程比调试 C/C 代码…

SpringSecurity+JWT前后端分离架构登录认证

目录 1. 数据库设计 2. 代码设计 登录认证过滤器 认证成功处理器AuthenticationSuccessHandler 认证失败处理器AuthenticationFailureHandler AuthenticationEntryPoint配置 AccessDeniedHandler配置 UserDetailsService配置 Token校验过滤器 登录认证过滤器接口配置…

C++将信息输入到文件内

第一步检查文件是否打开&#xff0c;用到头文件&#xff1a; #include <fstream> #include <sstream> 文件打开的函数为 file.isopen() 信息输入到文件应该为 file << "" << value; 注意是file<< 如图 定义file ofstream f…