组合模式
组合模式允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
——《Head First 设计模式》
也就是说,组合模式是用来呈现树状结构的,利用组合模式,让叶子节点和非叶子节点继承同一个基础类,可以让叶子节点对象和组件(非叶子)节点对象之间的差异得以忽略,从而为客户进程提供更简单统一的调用方式。
类图
从类图中可以看出,组件(非叶子节点)既继承了基础类,也拥有基础类作为一个属性。继承基础类是为了和叶子节点有同一个基础类,从而对客户端屏蔽组件和叶子节点的差异,让客户端有统一接口可以调用,方便客户端进程。拥有基础类作为一个属性是因为组件类不是叶子节点,其叶子节点的数据放在这个属性中。
例子
此处以部门为例子进行说明。假设A部门底下有B、C、D三个部门,C部门底下有E、F部门,B、D、E、F部门都没有子部门。部门之间的层次结构如下图所示
类图
抽象基础类
抽象类Dept中有一个抽象函数description,用于描述本部门的信息。另外三个函数add、remove、getChild在抽象基础类中提供默认实现,主要是考虑到叶子类的情况,这样叶子类继承后只需要实现description函数即可。而非叶子类需要重写这四个函数。因为add、remove、getChild这三个函数对非叶子类有意义而对叶子类无意义。
当然,对于add、remove、getChild这三个函数,也可以定义成抽象的,然后再在叶子类和非叶子类中分别对其进行特殊的处理。
1 |
abstract class |
叶子类
叶子类DeptLeaf中有一个属性name用于表示部门的名字,重写了description函数用于输出本部门的信息
1 |
class DeptLeaf extends Dept |
非叶子类
非叶子类DeptComposite有一个属性name用于表示本部门的名字,有一个属性deptList用于存储子部门,并重写了抽象类中的所有方法。对于description方法,主要是依次调用deptList属性中元素的description方法,这样就形成了递归调用,从而能够将本类及本类的所有子类遍历到。
1 |
class DeptComposite extends Dept |
验证进程
在此进程中,先构造了部门B、部门D、部门E、部门F、然后用部门E、部门F组成部门C、再用部门B、部门C、部门D组成部门A,从而完成部门的层次结构构造。然后遍历输出部门A的组织结构,再遍历输出部门B的组织结构,最后遍历输出部门C的组织结构
1 |
public class TestComposite |
输出如下
参考资料
[1] Eric Freeman等,Head First 设计模式(中文版)[M],北京:中国电力出版社,2007
原文引用 大专栏 https://www.dazhuanlan.com/2019/08/27/5d64bb8b77771/
原文地址:https://www.cnblogs.com/petewell/p/11418351.html
- WCF 4.0路由服务Routing Service
- ExpandableListView简单应用及listview模拟ExpandableListView
- 文件句柄与文件描述符
- android GifView分享
- VAE、GAN、Info-GAN:全解深度学习三大生成模型
- android获取设备唯一标示
- 如果正确读取SQL Server中的扩展事件?
- android自定义xmls文件属性
- 分布式系统中的RPC请求经常出现乱序的情况 写一个算法来将一个乱序的序列保序输出
- jsoup详解
- 用LogParser对IIS 日志进行分析
- android异步任务asyntask详解
- 在Mono 2.8上部署ASP.NET MVC 2
- java虚拟机构造原理
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- linux awk指令详解
- linux sed指令详解
- Grafana使用zabbix自定义模板
- linux shell之变量的使用规则
- 第11期:压缩表
- grafana-zabbix插件安装和配置zabbix mysql
- grafana使用教程之API key
- Grafana使用教程之安装
- Java基础数据类型之包装类equals和==详解
- SCP不用密码传输文件
- Java 使用Collections.reverse对list集合进行降序排序
- Liquibase异常 mysql数据库 Cannot add foreign key constraint
- Linux获取文件最后修改时间
- Crontab脚本无法正常执行问题
- Python 输入时间字符串以分钟单位计算时间差