组合模式是什么

组合模式(Composite Pattern),又叫部分整体模式,作为结构型模式,组合模式是用于把一组相似的对象当作一个单一的对象。组合多个对象形成树形结构来表示“整体-部分”的关系层次,它创建了对象组的树形结构。

组合模式能干什么

​ 它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

使用场景

部分、整体场景,如树形菜单,文件、文件夹的管理。

组合模式优缺点

优点

1、高层模块调用简单:组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;

2、节点自由增加:更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,

缺点

1、在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

2、设计较复杂,客户端需要花更多时间理清类之间的层次关系;

3、不容易限制容器中的构件;

组合模式的结构

  1. 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
  2. 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
  3. 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

辅助图示

树状辅助图

合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点,树形结构图如下。

示例代码图示

组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。

示例代码

1、抽象构件

public abstract class Component {abstract void add(Component c);abstract void remove(Component c);abstract Component getChild(int i);abstract int getNumber();abstract void operation();
}

2、容器节点

import java.util.ArrayList;public class CompositeEmployee extends Component{private String name;private String dept;private String position;private int salary;private ArrayList<Component> componentArrayList;public CompositeEmployee(String name, String dept, String position, int salary) {this.name = name;this.dept = dept;this.position = position;this.salary = salary;this.componentArrayList = new ArrayList<>(16);}@Overridevoid add(Component c) {if (!componentArrayList.contains(c)) componentArrayList.add(c);}@Overridevoid remove(Component c) {if (componentArrayList.contains(c)) componentArrayList.remove(c);}@OverrideComponent getChild(int i) {return componentArrayList.get(i) == null ? null : componentArrayList.get(i);}@Overrideint getNumber() {return componentArrayList.size();}/*** 在组合模式结构中,由于容器构件中仍然可以包含容器构件,* 因此在对容器构件进行处理时需要使用递归算法,* 即在容器构件的operation()方法中递归调用其成员构件的operation()方法。*/@Overridevoid operation() {if (position.equals("CEO")) this.salary += 2000;for (Object obj : componentArrayList) {Component component = (Component) obj;if(component instanceof CompositeEmployee) {((CompositeEmployee) component).setSalary(((CompositeEmployee) component).getSalary() + 1000);((Component) obj).operation();}else {((LeafEmployee) component).setSalary(((LeafEmployee) component).getSalary() + 500);}//do somthin}}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDept() {return dept;}public void setDept(String dept) {this.dept = dept;}public int getSalary() {return salary;}public void setSalary(int salary) {this.salary = salary;}@Overridepublic String toString() {return ("[ 姓名 : "+ name+", 所属部门 : "+ dept + ", " +"职位 :"+ position + ", " +"薪水 :" + salary+" ]");}
}

3、叶子节点

import java.io.PrintStream;public class LeafEmployee extends Component{private String name;private String dept;private String position;private int salary;public LeafEmployee(String name, String dept, String position, int salary) {this.name = name;this.dept = dept;this.position = position;this.salary = salary;}@Overridevoid add(Component c) {//do somthing}@Overridevoid remove(Component c) {//do somthing}@OverrideComponent getChild(int i) {//do somthingreturn null;}@Overrideint getNumber() {//do somthingreturn 0;}@Overridevoid operation() {//do somthingSystem.out.printf("我是员工 %d, 所属部门 %d, 薪水是 %d", name, dept, salary);}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDept() {return dept;}public void setDept(String dept) {this.dept = dept;}public String getPosition() {return position;}public void setPosition(String position) {this.position = position;}public int getSalary() {return salary;}public void setSalary(int salary) {this.salary = salary;}@Overridepublic String toString() {return (" [ 姓名 : "+ name+", 所属部门 : "+ dept + ", " +"职位 :"+ position + ", " +"薪水 :" + salary+" ]");}
}

4、Client

public class TestClient {public static void main(String[] args) {//定义CEOComponent componentCEO =new CompositeEmployee("John", "", "CEO", 40000);//定义TeamLeaderComponent componentTeamLealderOfJavaBackend =new CompositeEmployee("Robert", "JavaBackend", "TL", 25000);Component componentTeamLealderOfFrontEnd =new CompositeEmployee("Michel", "FrontEnd", "TL",25000);//定义普通员工Component componentFrontEndEmployee1 = new LeafEmployee("Bob", "FrontEnd", "Employee", 8000);Component componentFrontEndEmployee2 = new LeafEmployee("Laura", "FrontEnd",  "Employee",9000);Component componentJavaBackend1 = new LeafEmployee("Richard", "JavaBackend",  "Employee",9000);Component componentJavaBackend2 = new LeafEmployee("Rob", "JavaBackend",  "Employee",9000);//对员工进行装载componentCEO.add(componentTeamLealderOfJavaBackend);componentCEO.add(componentTeamLealderOfFrontEnd);componentTeamLealderOfJavaBackend.add(componentJavaBackend1);componentTeamLealderOfJavaBackend.add(componentJavaBackend2);componentTeamLealderOfFrontEnd.add(componentFrontEndEmployee1);componentTeamLealderOfFrontEnd.add(componentFrontEndEmployee2);//打印所有员工System.out.println(componentCEO);for (int i = 0; i < componentCEO.getNumber(); i++) {System.out.println(componentCEO.getChild(i));for (int i1 = 0; i1 < componentCEO.getChild(i).getNumber(); i1++) {System.out.println(componentCEO.getChild(i).getChild(i1));}}System.out.println("----------------------------------------------");componentCEO.operation();//为所有员工调薪一次System.out.println(componentCEO);for (int i = 0; i < componentCEO.getNumber(); i++) {System.out.println(componentCEO.getChild(i));for (int i1 = 0; i1 < componentCEO.getChild(i).getNumber(); i1++) {System.out.println(componentCEO.getChild(i).getChild(i1));}}}
}

运行结果

[ 姓名 : John, 所属部门 : , 职位 :CEO, 薪水 :40000 ]
[ 姓名 : Robert, 所属部门 : JavaBackend, 职位 :TL, 薪水 :25000 ][ 姓名 : Richard, 所属部门 : JavaBackend, 职位 :Employee, 薪水 :9000 ][ 姓名 : Rob, 所属部门 : JavaBackend, 职位 :Employee, 薪水 :9000 ]
[ 姓名 : Michel, 所属部门 : FrontEnd, 职位 :TL, 薪水 :25000 ][ 姓名 : Bob, 所属部门 : FrontEnd, 职位 :Employee, 薪水 :8000 ][ 姓名 : Laura, 所属部门 : FrontEnd, 职位 :Employee, 薪水 :9000 ]
----------------------------------------------
[ 姓名 : John, 所属部门 : , 职位 :CEO, 薪水 :42000 ]
[ 姓名 : Robert, 所属部门 : JavaBackend, 职位 :TL, 薪水 :26000 ][ 姓名 : Richard, 所属部门 : JavaBackend, 职位 :Employee, 薪水 :9500 ][ 姓名 : Rob, 所属部门 : JavaBackend, 职位 :Employee, 薪水 :9500 ]
[ 姓名 : Michel, 所属部门 : FrontEnd, 职位 :TL, 薪水 :26000 ][ 姓名 : Bob, 所属部门 : FrontEnd, 职位 :Employee, 薪水 :8500 ][ 姓名 : Laura, 所属部门 : FrontEnd, 职位 :Employee, 薪水 :9500 ]

GOF设计模式之组合设计模式(结构型模式) ✨ 每日积累相关推荐

  1. 设计模式(三)结构型模式介绍及实例

    文章目录 一.适配器模式 1.1 适配器模式定义 1.2 适配器模式主要角色 1.3 适配器模式特点 1.4 适配器模式实现方式 1.4.1 类适配器模式 1.4.2 对象适配器模式 1.5 适配器模 ...

  2. 《设计模式详解》结构型模式 - 组合模式

    组合模式 5.6 组合模式 5.6.1 概述 5.6.2 结构 5.6.3 案例实现 5.6.4 组合模式的分类 5.6.5 优点 5.6.6 使用场景 完整的笔记目录:<设计模式详解>笔 ...

  3. 设计模式(四)结构型模式

    前言 结构型设计模式,主要研究: 主要有哪些场景使用结构型设计模式: 每种场景应该使用何种设计模式: 以程序中的功能为核心,研究程序功能的组织结构.所以这一章,我们要把"功能结构" ...

  4. 《设计模式详解》结构型模式 - 外观模式

    外观模式 5.5 外观模式 5.5.1 概述 5.5.2 结构 5.5.3 案例 5.5.4 使用场景 5.5.5 Tomcat 源码 完整的笔记目录:<设计模式详解>笔记目录,欢迎指点! ...

  5. 《设计模式详解》结构型模式 - 桥接模式

    桥接模式 5.4 桥接模式 5.4.1 概述 5.4.2 结构 5.4.3 案例 5.4.4 使用场景 完整的笔记目录:<设计模式详解>笔记目录,欢迎指点! 结构型模式描述如何将类或对象按 ...

  6. 《设计模式详解》结构型模式 - 适配器模式

    适配器模式 5.2 适配器模式 5.2.1 概述 5.2.2 结构 5.2.3 类适配器模式 5.2.4 对象适配器模式 5.2.5 接口适配器模式 5.2.6 应用场景 5.2.7 JDK 源码 - ...

  7. 《设计模式详解》结构型模式 - 代理模式

    代理模式 5.1 代理模式 5.1.1 概述 5.1.2 结构 5.1.3 静态代理 5.1.4 动态代理 JDK 动态代理 JDK 动态代理分析 CGLIB 动态代理 5.1.5 三种代理的对比 5 ...

  8. 设计模式(2)结构型模式

    结构型模式 结构型模式介绍如何将对象和类组装成较大的结构, 并同时保持结构的灵活和高效. 结构型模式: 适配器模式:用来把一个接口转化成另一个接口.使得原本由于接口不兼容而不能一起工作的那些类可以在一 ...

  9. Java设计模式笔记——七个结构型模式

    系列文章目录 第一章 Java设计模式笔记--七大设计原则 第二章 Java设计模式笔记--六个创建型模式 文章目录 系列文章目录 一.适配器模式 1.概念 2.类适配器 3.对象适配 4.缺省适配器 ...

最新文章

  1. vega8显卡和mx250哪个好_2020轻薄本推荐 (MX350显卡)
  2. python reader循环_python – 多次循环遍历csv.DictReader行
  3. BZOJ4668: 冷战 [并查集 按秩合并]
  4. Unix调试工具dbx使用方法
  5. smartforms句柄与以簇的方式存储数据。
  6. 《C++编程风格(修订版)》——2.5 动态内存的一致性
  7. 如何从ios酷我音乐盒中导出已下载的音乐文件(使用Java编程实现)
  8. 【★原创★】夜晚,不要让电白白流失!
  9. paip.动画透明淡入淡出窗口之重绘性能
  10. 全网详细接口测试ApiPost详细教程(实战),吐血整理
  11. 苹果6显示连接id服务器出错,appleid:appleid连接失败该如何解决
  12. java多线程对Runnable和Thread的理解及简述,内附实例。
  13. python分词考研英语真题词频(附结果)——读取word、nltk、有道智云API
  14. 0x80073712(0x80073712解决方法)
  15. java怎么打印星期,在任何日期打印出星期几
  16. Facebook要做的事,这家公司4年前就在做了
  17. 91.p58.space http://email.91dizhi.at.gmail.com06监测模块测试入口index.php
  18. mysql事务重点知识总结(需要完整脑图的可以联系我)
  19. 内置超声波振动筛换能器振子设计
  20. 数据库学习笔记:事务的特性和隔离级别

热门文章

  1. 俄方产量也将削减恐左右油价未来走势
  2. RabbitMQ消息队列工作原理及集成使用
  3. 内涵TV段子,价值500元的dz内涵笑话商业源码
  4. 有苦有乐的算法 --- 有序数组中的元素存在问题、最左元素问题和无序数组局部最小问题
  5. 【SW7203】智融新料号SW7203,支持1-4S,双向升降压,路径管理,可搭配SW2303,实现车充、移动电源100W
  6. 计算机科学技术专业解析,计算机科学与技术专业怎么样 主要学什
  7. 语音标注的具体应用场景
  8. 计算机实践教程采莲趣事,计算机基础作业采莲趣事
  9. 【洛谷P3960】列队题解
  10. 在传染病中,肠道微生物-免疫力-营养在优化治疗策略中的作用