对组合模式的理解

目录

  • 一、场景
    • 1、题目描述 【[案例来源](https://kamacoder.com/problempage.php?pid=1090)】
    • 2、输入描述
    • 3、输出描述
    • 4、输入示例
    • 5、输出示例
  • 二、实现(假的组合模式)
    • 1、代码
    • 2、为什么上面的写法是假的组合模式?
  • 三、实现(真的组合模式)
    • 1、案例来源的实现
    • 2、我的实现
  • 四、个人思考

一、场景

设计模式很依赖场景,通过场景也能更好理解这种模式解决了什么问题。

  • 无论是学校还是公司,都存在组织结构。而且,这种结构多半是树状结构。
  • 当类与类之间的结构也需要表达成树状结构时,组合模式就来大显身手了。

1、题目描述 【案例来源】

小明所在的公司内部有多个部门,每个部门下可能有不同的子部门或者员工。
请你设计一个组合模式来管理这些部门和员工,实现对公司组织结构的统一操作。部门和员工都具有一个通用的接口,可以获取他们的名称以及展示公司组织结构。

2、输入描述

第一行是一个整数 N(1 <= N <= 100),表示后面有 N 行输入。
接下来的 N 行,每行描述一个部门或员工的信息。部门的信息格式为 D 部门名称,员工的信息格式为 E 员工名称,其中 D 或 E 表示部门或员工。

3、输出描述

输出公司的组织结构,展示每个部门下的子部门和员工

4、输入示例

MyCompany
8
D HR
E HRManager
D Finance
E AccountantA
E AccountantB
D IT
E DeveloperA
E DeveloperB

5、输出示例

Company Structure:
MyCompany
HR
HRManager
Finance
AccountantA
AccountantB
IT
DeveloperA
DeveloperB

二、实现(假的组合模式)

1、代码

public interface Component {String showName();
}public class Company implements Component {private final String name;@Setterprivate List<Department> departments;public Company(String name) {this.name = name;}public void addDepartment(Department department) {if (CollectionUtils.isEmpty(departments)) {departments = new ArrayList<>();departments.add(department);} else {departments.add(department);}}@Nullablepublic Department gotLastDepartment() {if (CollectionUtils.isEmpty(departments)) {return null;} else {return departments.get(departments.size() - 1);}}@Overridepublic String showName() {return name;}public String showCompanyStructure() {StringBuilder sb = new StringBuilder("Company Structure:\n").append(showName()).append("\n");Optional.ofNullable(departments).ifPresent(departments -> departments.stream().filter(Objects::nonNull).forEach(department -> {sb.append("  ").append(department.showName()).append("\n");Optional.ofNullable(department.getEmployees()).ifPresent(employees -> {employees.stream().forEach(employee -> sb.append("    ").append(employee.showName()).append("\n"));});}));return sb.toString();}
}@Data
public class Department implements Component {private String name;private List<Employee> employees;public Department(String name) {this.name = name;}@Overridepublic String showName() {return this.name;}public void addEmployee(Employee employee) {if (CollectionUtils.isEmpty(employees)) {employees = new ArrayList<>();employees.add(employee);} else {employees.add(employee);}}
}@AllArgsConstructor
public class Employee implements Component {private String name;@Overridepublic String showName() {return name;}
}
public class Application {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String companyName = scanner.nextLine();Company company = new Company(companyName);int n = scanner.nextInt();for (int i = 0; i < n; i++) {String type = scanner.next();String name = scanner.next();if (StringUtils.equals(type, "D")) {company.addDepartment(new Department(name));} else if (StringUtils.equals(type, "E")) {Department department = company.gotLastDepartment();department.addEmployee(new Employee(name));}}System.out.printf(company.showCompanyStructure());}
}

2、为什么上面的写法是假的组合模式?

  • 场景中的公司结构:
    在这里插入图片描述
    • 对这个结构进行建模,不应该是:
public class Company implements Component {private final String name;@Setterprivate List<Department> departments;
}public class Department implements Component {private String name;private List<Employee> employees;
}public class Employee implements Component {private String name;
}
  • 因为上图实际上有2个基本结构:
// Company-Department (1 对 n)、Department-Employee(1对n)
class Composite implements Component {private String name;private List<Component> children;
}// 这个便是Employee
class Leaf implements Component {private String name;
}
  • 所以,没有Get到这一点,就容易写出假的组合模式。(写的时候也会发现写的很累)

三、实现(真的组合模式)

1、案例来源的实现

  • 场景中题目的提供方,也给出了相应的实现:
public interface Component {void display(int depth);
}public class Department implements Component {private String name;private List<Component> children;public Department(String name) {this.name = name;this.children = new ArrayList<>();}public void add(Component component) {children.add(component);}@Overridepublic void display(int depth) {StringBuilder indent = new StringBuilder();for (int i = 0; i < depth; i++) {indent.append("  ");}System.out.println(indent + name);for (Component component : children) {component.display(depth + 1);}}
}public class Employee implements Component {private String name;public Employee(String name) {this.name = name;}@Overridepublic void display(int depth) {StringBuilder indent = new StringBuilder();for (int i = 0; i < depth; i++) {indent.append("  ");}System.out.println(indent + "  " + name);}
}public class Company {private String name;private Department root;public Company(String name) {this.name = name;this.root = new Department(name);}public void add(Component component) {root.add(component);}public void display() {System.out.println("Company Structure:");root.display(0); // 从 1 开始,以适配指定的缩进格式}public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);
// 读取公司名称String companyName = scanner.nextLine();Company company = new Company(companyName);
// 读取部⻔和员工数量int n = scanner.nextInt();scanner.nextLine(); // 消耗换行符
// 读取部⻔和员工信息for (int i = 0; i < n; i++) {String type = scanner.next();String name = scanner.nextLine().trim();if ("D".equals(type)) {Department department = new Department(name);company.add(department);} else if ("E".equals(type)) {Employee employee = new Employee(name);company.add(employee);}}
// 输出公司组织结构company.display();}
}
  • debug会发现,这并没有正确表示company的结构:
    在这里插入图片描述
  • 那为啥能输出这样的结果呢?
MyCompanyHRHRManagerFinanceAccountantAAccountantBITDeveloperADeveloperB
  • 原因在于:
public class Employee implements Component {...@Overridepublic void display(int depth) {StringBuilder indent = new StringBuilder();for (int i = 0; i < depth; i++) {indent.append("  ");}System.out.println(indent + "  " + name); // 这里的depth实际上是1,因此作者多加了"  "}
}

显然,这并不是正确的实现。

2、我的实现

public interface Component {void showName(int depth);
}public class Composite implements Component {private String name;private List<Component> children;public Composite(String name) {this.name = name;children = new ArrayList<>();}public void addComponent(Component component) {children.add(component);}public Composite gotLastComposite() {if (!children.isEmpty()) {Component component = children.get(children.size() - 1);if (component instanceof Composite) {return (Composite) component;} else {throw new RuntimeException("last component is not composite");}} else {throw new RuntimeException("doesn't exist last component");}}@Overridepublic void showName(int depth) {System.out.println(StringUtils.repeat("  ", depth) + name);for (Component child : children) {child.showName(depth + 1);}}
}@AllArgsConstructor
public class Employee implements Component {private String name;@Overridepublic void showName(int depth) {System.out.println(StringUtils.repeat("  ", depth) + name);}
}public class Company extends Composite {public Company(String name) {super(name);}@Overridepublic void showName(int depth) {System.out.println("Company Structure:");super.showName(depth);}
}
public class Application {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);String companyName = scanner.nextLine();Company company = new Company(companyName);int n = scanner.nextInt();for (int i = 0; i < n; i++) {String type = scanner.next();String name = scanner.next();if (StringUtils.equals(type, "D")) {company.addComponent(new Composite(name));} else if (StringUtils.equals(type, "E")) {Composite department = company.gotLastComposite();department.addComponent(new Employee(name));}}company.showName(0);}
}
  • Company的结构:
    在这里插入图片描述

四、个人思考

  • 对真实场景建模后,类呈现树状结构,那么可以尝试使用组合模式设计代码:
class Composite implements Component {private String name;private List<Component> children;
}// 这个便是Employee
class Leaf implements Component {private String name;
}

组合模式:实现接口A + 组合多个接口A

  • 装饰模式、桥接模式都用到了组合的理念,但都是一对一的形式:
  • 装饰模式:实现接口A + 组合接口A
public class EncryptDataSourceImpl implements DataSource {private DataSource dataSource;
}
  • 桥接模式:实现接口A + 组合接口B
public class Circle implements Shape {private Color color;
}

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

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

相关文章

文本生成任务的评价方法BLEU 和 ROUGE

BLEU 是 2002 年提出的&#xff0c;而 ROUGE 是 2003 年提出的。这两种指标虽然存在着一些问题&#xff0c;但是仍然是比较主流的评价指标。 BLUE BLEU 的全称是 Bilingual evaluation understudy&#xff0c;BLEU 的分数取值范围是 0&#xff5e;1&#xff0c;分数越接近1&a…

YOLOv9改进策略 | 细节创新篇 | 迭代注意力特征融合AFF机制创新RepNCSPELAN4

一、本文介绍 本文给大家带来的改进机制是AFF&#xff08;迭代注意力特征融合&#xff09;&#xff0c;其主要思想是通过改善特征融合过程来提高检测精度。传统的特征融合方法如加法或串联简单&#xff0c;未考虑到特定对象的融合适用性。iAFF通过引入多尺度通道注意力模块(我…

算法打卡day52|单调栈篇03| 84.柱状图中最大的矩形

算法题 Leetcode 84.柱状图中最大的矩形 题目链接:84.柱状图中最大的矩形 大佬视频讲解&#xff1a;84.柱状图中最大的矩形视频讲解 个人思路 这题和接雨水是相似的题目&#xff0c;原理上基本相同&#xff0c;也是可以用双指针和单调栈解决&#xff0c;只是有些细节不同。…

锦瑟香也MYLOVE:音质与颜值俱佳,入坑HiFi的热门好物!

当下尽管无线耳机大行其道&#xff0c;但有线耳机依旧保有其独特的魅力&#xff0c;特别是在音质表现上&#xff0c;它们拥有无线耳机难以企及的优势。如果对音质要求很高的话&#xff0c;口袋里还是少不了一副有线耳机。国产品牌中就有许多性价比高的有线耳机&#xff0c;它们…

Django admin后台添加自定义菜单和功能页面

django admin是根据注册的模型来动态生成菜单&#xff0c;从这个思路出发&#xff0c;如果想添加自定义菜单&#xff0c;那就创建一个空模型并且注册。步骤如下&#xff1a; 1、创建空模型&#xff1a; class ResetSVNAuthFileModel(models.Model):"""仅用来显…

《MATLAB科研绘图与学术图表绘制从入门到精通》示例:绘制伊甸火山3D网格曲面图

11.4.2小节我们使用3D曲面图可视化分析伊甸火山数据&#xff0c;本小节我们采用3D网格曲面图可视化分析伊甸火山数据&#xff0c;以展示其地形&#xff0c;具体示例代码如下。 购书地址&#xff1a;https://item.jd.com/14102657.html

Django数据导出与导入问题

执行: python manage.py loaddata data.json 的常见错误: * 1. UnicodeDecodeError: utf-8 codec cant decode byte 0xff in position 0: invalid start byte* 2. raise JSONDecodeError("Unexpected UTF-8 BOM (decode using utf-8-sig)",...django.core.serializer…

css animation 动画详细学习

学习 CSS 动画是一个深入且富有创造性的过程&#xff0c;它允许开发者创建出引人入胜且交互性强的网页效果。以下是对 CSS 动画学习的一些总结和要点&#xff1a; 1. 关键帧动画&#xff08;keyframes&#xff09; 使用 keyframes 规则定义动画的整个过程。在 keyframes 中&a…

聚道云软件连接器助力企业实现滴滴出差报销自动化

一、客户介绍 某机械有限公司是一家在机械设备制造领域拥有深厚底蕴和卓越实力的企业。自公司成立以来&#xff0c;该公司始终秉承创新、务实、高效的发展理念&#xff0c;专注于机械设备的研发、生产和销售。经过多年的发展&#xff0c;公司已成为国内机械行业的佼佼者&#…

RocketMQ异步消息发送失败重试DEMO

producer.setRetryTimesWhenSendAsyncFailed(3); 都知道通过设置&#xff0c;尝试是在MQClientAPIImpl 中完成 其重试是通过MQClientAPIImpl的onExceptionImpl方法来实现&#xff0c;它会先判断重试次数&#xff0c;然后重新调用sendMessageAsync方法进行重试&#xff0c;调用…

新手必看!嵌入式STM32-PID

本文目录 一、知识点1. 位置式pid&#xff08;1&#xff09;公式&#xff08;2&#xff09;代码 2. 串级PID简易代码 一、知识点 1. 位置式pid &#xff08;1&#xff09;公式 &#xff08;2&#xff09;代码 pid.c typedef struct PID {float Kp; // Proportion…

高效编程工具 JetBrains CLion 2024 中文激活 mac/win

在追求编程高效与精准的道路上&#xff0c;JetBrains CLion 2024 for Mac无疑是您的最佳伙伴。这款专为Mac用户打造的C/C集成开发环境&#xff0c;凭借其强大的功能和出色的性能&#xff0c;赢得了广大开发者的青睐。 CLion 2024拥有智能的代码编辑器和强大的代码分析工具&…

pycharm已有项目增加pipenv

pycharm已有项目增加pipenv 第一步 第一步 python base 需要安装pipenv pip install pipenv在设置&#xff0c;project 之后 会自动查找项目下的pipfile 和pipfile.lock 进行pip配置 如果网络较慢&#xff0c;可以修复pipfile下的url 为国内的pip源 [[source]] name "…

Linux入门学习 之 基础操作指令讲解(小白必看)

股票的规律找到了&#xff0c;不是涨就是跌 一、Linux下基本指令 1.ls 指令 2.pwd 命令 3.cd 指令 4.touch 指令 5.mkdir 指令 6.rmdir指令 && rm 指令 7.man 指令 8.cp 指令 9.mv指令 10.cat 11.more 指令 12.less 指令 13.head 指令 14.tail 指令 15…

新兴存内计算芯片架构、大型语言模型、多位存内计算架构——存内计算架构的性能仿真与对比分析探讨

CSDN存内社区招募&#xff1a;https://bbs.csdn.net/forums/computinginmemory? 首个存内计算开发者社区&#xff0c;现0门槛新人加入&#xff0c;发文享积分兑超值礼品&#xff1b; 存内计算先锋/大使在社区投稿&#xff0c;可获得双倍积分&#xff0c;以及社区精选流量推送…

Redis进阶——点赞和点赞排行

目录 发布达人探店笔记实现步骤 查看探店笔记点赞功能问题分析&#xff1a;功能完善具体实现 点赞排行榜实现需求实现步骤 发布达人探店笔记 实现类似于大众点评的发布个人笔记的效果 实现步骤 准备数据表如下&#xff1a; SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS 0;…

与助听器相关的职业主要有哪些?

助听装置是目前解决听觉障碍的几乎唯一科学的方法。然而助听装置改变的不是听力&#xff0c;而是外界的声音信息。也就是助听装置只能将外界的声音信息改变成能够适应听觉障碍患者听觉动态范围的声音。显然助听器并不知道听觉障碍患者的听觉动态范围是多少&#xff1f;也不知道…

分布式系统——全站监控

文章目录 全站监控要点**监控范围与对象****监控指标与数据****监控工具与技术****监控策略与实践****全站监控的价值** 实例展示 全站监控要点 全站监控是针对分布式架构中所有组件和服务进行全方位、多层次、实时的性能监控、状态检测和故障告警的系统化方法。在分布式环境下…

PMP每年考几次,费用如何?

今年的的考试分别分布在3月、6月、8月、11月&#xff0c;一般来说PMP的考试时间是3、6、9、12月&#xff0c;如果有特殊情况PMI也会及时进行调整&#xff0c;具体看他们官网的通知了。 PMP的考试费用全球是统一的&#xff0c;在国内考试报名费用是3900元&#xff0c;如果考试没…

【学习】自动化测试有哪些优势和不足

在当今这个数字化时代&#xff0c;软件测试已经成为了任何一款产品成功的关键因素之一。而在诸多的测试方法中&#xff0c;自动化测试凭借着其独特的魅力吸引着越来越多的企业。今天就让我们一起走进自动化测试的世界&#xff0c;探讨它的优势与不足。 一、自动化测试优势 1.…