组合模式的定义:又叫作整体-部分(Part-Whole)模式,通过将单个对象(叶节点)和组合对象用相同的接口表示,使客户端对单个对象和组合对象的访问具有一致性。它是一种将对象组合成树状的层次结构的模式。属于结构型设计模式。

组合模式一般用来描述整体与部分的关系,它将对象组合到树状结构,顶层的节点被称为根节点,最末级的节点成为叶节点,中间的节点成为树枝节点,树形结构如下图。

由上图可以看出,根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用;而叶节点与树枝节点在语义上不属于同一种类型,但是在组合模式中,我们会把树枝节点和叶节点看作同一种数据类型(用统一接口定义),让它们具备一致行为。这样,在组合模式中,整个树形结构中的对象都属于同一种类型,客户端不需要辨别是树枝节点还是叶子节点,可以直接进行操作,给客户端的使用带来极大的便利。

组合模式的结构:组合模式包含以下3个角色。

  1. 抽象根节点(Component):为叶节点和树枝节点声明公共接口,并实现它们的默认行为。
  2. 树叶节点(Leaf):组合中的叶节点对象,它没有子节点,是树状结构的最末级。
  3. 树枝节点(Composite):组合中的分支节点对象,它有子节点,主要作用是存储和管理子节点。

组合模式的实现:组合模式分为透明式组合模式和安全式组合模式。我们以公司组织架构为例,分别用透明式组合模式和安全式组合模式实现。

某公司组织架构如下图,公司包括销售部、研发部和财务部,销售部和财务部下又分为A组和B组。

透明组合模式的实现:

在透明组合模式中,抽象根节点声明了所有子类中的全部方法,客户端无须区别叶节点和树枝节点,它们具备一致的接口,对客户端来说是透明的。但其缺点是:叶节点本来没有增加 Add()、删除Remove() 及 获取子节点GetChild() 的方法,却要实现它们(空实现或抛出异常),这样会带来一些安全性问题。

//抽象根节点
public interface DeptComponent {void add(DeptComponent deptComponent);void remove(DeptComponent deptComponent);List<DeptComponent> getChildren();void getName();
}//叶节点
public class LeafDept implements DeptComponent {private String name;public LeafDept(String name){this.name = name;}@Overridepublic void add(DeptComponent deptComponent) { }@Overridepublic void remove(DeptComponent deptComponent) { }@Overridepublic List<DeptComponent> getChildren() {return null;}@Overridepublic void getName() {System.out.println(name+"前来报到!");}
}//树枝节点
public class CompositeDept implements DeptComponent{private List<DeptComponent> children = new ArrayList<>();private String name;CompositeDept(String name){this.name = name;}@Overridepublic void add(DeptComponent deptComponent) {children.add(deptComponent);}@Overridepublic void remove(DeptComponent deptComponent) {children.remove(deptComponent);}@Overridepublic List<DeptComponent> getChildren() {return children;}@Overridepublic void getName() {System.out.println(name+"前来报到!");}
}//测试类
public class CompositeTest {public static void main(String[] args) {DeptComponent company = new CompositeDept("某公司");DeptComponent saleDept = new CompositeDept("销售部");DeptComponent developmentDept = new CompositeDept("研发部");DeptComponent financeDept = new CompositeDept("财务部");DeptComponent saleA = new LeafDept("销售部A组");DeptComponent saleB = new LeafDept("销售部B组");DeptComponent developmentA = new LeafDept("研发部A组");DeptComponent developmentB = new LeafDept("研发部B组");developmentDept.add(developmentA);developmentDept.add(developmentB);saleDept.add(saleA);saleDept.add(saleB);company.add(saleDept);company.add(developmentDept);company.add(financeDept);List<DeptComponent> children = company.getChildren();children.stream().forEach(deptComponent -> {deptComponent.getName();deptComponent.getChildren().stream().forEach(deptComponent1 -> deptComponent1.getName());});}
}

透明组合模式的结构图:

安全组合模式的实现:

在安全组合模式中,将管理叶节点的方法移到树枝节点中,抽象根节点和叶节点没有对子对象的管理方法,避免了透明组合模式的安全性问题,但由于叶节点和树枝节点有不同的接口,客户端在调用时要知道叶节点和树枝节点的存在,所以失去了透明性。

//抽象根节点
public interface DeptComponent {void getName();
}//叶节点
public class LeafDept implements DeptComponent {private String name;public LeafDept(String name){this.name = name;}@Overridepublic void getName() {System.out.println(name+"前来报到!");}
}//树枝节点
public class CompositeDept implements DeptComponent{private List<DeptComponent> children = new ArrayList<>();private String name;CompositeDept(String name){this.name = name;}public void add(DeptComponent deptComponent) {children.add(deptComponent);}public void remove(DeptComponent deptComponent) {children.remove(deptComponent);}public List<DeptComponent> getChildren() {return children;}@Overridepublic void getName() {System.out.println(name+"前来报到!");}
}//测试类
public class CompositeTest {public static void main(String[] args) {CompositeDept company = new CompositeDept("某公司");CompositeDept saleDept = new CompositeDept("销售部");CompositeDept developmentDept = new CompositeDept("研发部");CompositeDept financeDept = new CompositeDept("财务部");DeptComponent saleA = new LeafDept("销售部A组");DeptComponent saleB = new LeafDept("销售部B组");DeptComponent developmentA = new LeafDept("研发部A组");DeptComponent developmentB = new LeafDept("研发部B组");developmentDept.add(developmentA);developmentDept.add(developmentB);saleDept.add(saleA);saleDept.add(saleB);company.add(saleDept);company.add(developmentDept);company.add(financeDept);List<DeptComponent> children = company.getChildren();children.stream().forEach(deptComponent -> {deptComponent.getName();if(deptComponent instanceof CompositeDept){CompositeDept compositeDept = (CompositeDept) deptComponent;compositeDept.getChildren().stream().forEach(deptComponent1 -> deptComponent1.getName());}});}
}

安全组合模式的结构图:

组合模式的优点:

  1. 组合模式使客户端处理单个对象和组合对象逻辑一致,这简化了客户端代码;
  2. 更容易在组合体内加入新的对象,满足“开闭原则”;

组合模式的缺点:

  1. 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
  2. 不容易限制容器中的构件;
  3. 不容易用继承的方法来增加构件的新功能;

组合模式的使用场景:

  1. 在需要表示一个对象整体与部分的层次结构的场合。
  2. 要求对客户端隐藏组合对象与单个对象的差异,使客户端可以用统一的接口使用组合结构中的所有对象的场合。

设计模式系列:搞懂组合模式,单对象与组合对象对外统一接口相关推荐

  1. php 规格,PHP 设计模式系列之 specification规格模式_PHP

    Plus.php left = $left; $this->right = $right; } /** * 返回两种规格的逻辑与评估 * * @param Item $item * * @ret ...

  2. 设计模式系列——三个工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)...

    转自:http://www.cnblogs.com/stonehat/archive/2012/04/16/2451891.html 设计模式系列--三个工厂模式(简单工厂模式,工厂方法模式,抽象工厂 ...

  3. C++两个函数可以相互递归吗_[算法系列] 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进

    [算法系列] 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进 从学习写代码伊始, 总有个坎不好迈过去, 那就是遇上一些有关递归的东西时, 看着简短的代码, 怎么稀里糊涂就出来了. ...

  4. 一个案例搞懂工厂模式和单例模式

    一个案例搞懂工厂模式和单例模式 1 单例模式 一个对象只有一个实例 单例类必须自己创建自己的唯一实例. 单例类必须给所有其他对象提供这一实例. 注意:所有的单例模式,应当使其构造方法私有化. 1.1 ...

  5. [算法系列] 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进

    [算法系列] 搞懂递归, 看这篇就够了 !! 递归设计思路 + 经典例题层层递进 从学习写代码伊始, 总有个坎不好迈过去, 那就是遇上一些有关递归的东西时, 看着简短的代码, 怎么稀里糊涂就出来了. ...

  6. Java设计模式之组合模式(透明组合模式,安全组合模式)

    一.概述 组合多个对象形成树形结构以表示具有部分-整体关系的层次结构,可以让客户端统一对待单个对象和组合对象. 组合模式关注那些包含叶子构件和容器构件的结构以及它们的组织形式,在叶子构件中不包含成员变 ...

  7. 组合模式——透明组合模式,安全组合模式

    组合模式 概述 叶子节点进行相关的操作. 可以将这颗树理解成一个大的容器,容器里面包含很多的成员对象,这些成员对象即可是容器对象也可以是叶子对象. 但是由于容器对象和叶子对象在功能上面的区别,使得我们 ...

  8. 组合模式详解附有代码案例分析(包含透明组合模式、安全组合模式的代码示例)

    组合模式 一.组合模式的概念和角色 (一).组合模式的概念 (二).组合模式的角色 二.组合模式的应用场景 三.透明组合模式的代码示例 四.安全组合模式的代码示例 五.组合模式的优缺点 (一).优点 ...

  9. js组合模式和寄生组合模式的区别研究

    最近在阅读<js权威指南>的继承这一章,对于组合模式和寄生组合模式的区别有点混淆,在多次重读以及尝试之后,得到一些心得. 组合模式继承 结合了构造函数继承时可以为每个属性重新初始化,构造一 ...

最新文章

  1. 1.磁盘的数据结构包括那些内容?
  2. 语言专升本必背代码_2020年【山西省专升本】,专升本专业与考试科目,专升本招生院校,专升本报名流程大全!...
  3. leetcode738. 单调递增的数字
  4. Lombok,一种编译时Java注释预处理器,可最大程度地减少代码大小
  5. Intel Core Enhanced Core架构/微架构/流水线 (9) - 执行单元发射口旁路时延
  6. 抽帧定格动画如何制作?AE制作哈利波特定格动画教程
  7. 利用Pano2VR在全景图中添加视频,音频,图片
  8. 计算机建立局域网共享,如何建立局域网共享
  9. 计算机的标点符号有哪些,电脑标点符号怎么打出来,四个电脑小技巧轻松输入各种符号...
  10. 疯狂的程序员_戴蓓会客厅第13期|疯狂的程序员 三维家蔡志森的野心
  11. css朗逸保险丝盒机舱,【朗逸保险盒】朗逸保险盒位置图解、拆卸方法_车主指南...
  12. 数据分析精选案例:3行代码上榜Kaggle学生评估赛
  13. 集成电路光刻机精密运动台控制方法
  14. JS实现滚动栏的效果
  15. 精准医学:NGS和MFC方法在多发性骨髓瘤MRD评估中的比较|预后监测
  16. 深圳宝安周边公司出行团建户外一日游
  17. 欧氏空间位姿与变换矩阵的转换
  18. 线性代数回顾——协方差与逆矩阵
  19. 微型计算机组装的目的,微机组装实训报告范文
  20. Unity3D游戏作品大盘点

热门文章

  1. 珠海公共自行车系统分析系列 - 查询系统
  2. 集成学习-Voting
  3. 集成学习-bagging算法
  4. Benchmarking Detection Transfer Learning with Vision Transformers(2021-11)
  5. 物联网改变我们的生活连接万物
  6. 【内含实物图】一款可独立行走且支持远程对话的微型巡逻摄像头——嵌入式方案
  7. 切图小贴士-手机Android平台“点九”的切图
  8. 【计算机系统基础】符号表、符号解析(详解)
  9. ERP系统是什么?ERP实施顾问怎么做?
  10. 三维程序/游戏制作基本常识