一. 定义
在现实生活中存在很多 “部分-整体”的关系.如大学中的部门与学院,文件系统中的文件与文件夹,对这些对象的处理,可用组合模式实现。
1>又叫部分整体(Part-Whole)模式,它是一种将对象组合成树状的层次结构,以表示"整体-部分"的层次关系;
2>这种类型的设计模式属于结构型模式;
3>组合模式使得客户端对单个对象和组合对象的访问具有一致性,即:组合能让客户以一致的方式处理个别对象以及组合对象;
二. 特点
由上图可以看出,其根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用,而叶子节点与树枝节点在语义上不属于同一种类型,但是在组合模式中,会把树枝节点和叶子节点看作属于同一种数据类型(用统一接口定义),让他们具备一致行为。使得用户不用辨别,可直接操作。
1. 优点
1>简化客户端操作,客户端只需面对一致的对象而不用考虑整体部分或节点叶子的问题;
2>具有较强的扩展性,当我们更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动;
3>方便创建复杂的层次结构,客户端不用理会组合里面的组织细节,容易添加节点或叶子从而创建出复杂的树形结构;
2. 缺点
要求较高的抽象性,如节点和叶子有很多差异性的话,比如很多方法和属性不一样,不适合使用组合模式;
三. 应用场景
1.需要遍历组织机构,或处理的对象具有树形结构时,非常适合使用组合模式;
2.需求对用户隐藏组合对象与单个对象的不同,用户可以用统一的接口使用组合结构中的所有对象的场合。
3.使用组合模式需要确保有相似方法及属性的几个对象,不如这里的学校,学院就有相似的输出方法;
四. 模式的结构
将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,以避免安全性问题,
但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。
组合模式结构图
组合模式角色分析
-
Component(抽象构件):
为叶子节点和树枝节点声明公共接口,并实现它们的默认行为, 在透明式的组合中抽象构件还声明访问和管理子类的接口;
在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝结点完成(总的抽象类定义一些通用的方法:新增、删除)。
-
Leaf(叶子节点):作为被管理者无子节点不能管理孩子,但它定义了组合内元素的行为;
-
Composite(树枝结点):可存储和管理叶子和子节点,但不具叶子的某些行为,通常包含add(),remove(),getChild()等方法;
五. 模式的实现
假如要访问集合 c0={leaf1,{leaf2,leaf3}} 中的元素,其对应的树状图如图 3 所示。
需求:解决学校院系展示存在的问题
编程展示一个学校院系结构,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系,关系如下:
------清华大学-----
-----计算机学院-----
软件工程
网络工程
-----信息工程学院----
通信工程
信息工程
1.传统方案解决
将学院看做是学校的子类,系是学院的子类,这样实际上是站在组织大小的维度进行分层的;
实际上我们要求在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系,因此这种方案,不能很好实现 管理操作,比如对学院,系的添加,删除,遍历等;
2.使用组合模式解决
把学校、院、系都看做是组织结构,它们之间没有继承的关系,而是一个树形结构,可更好的实现 管理操作;
1> 实例结构图
2> 相关代码实现
public class CompositeClient {
public static void main(String[] args) {
//从大到小创建对象 学校
University university = new University("清华大学");
//创建学院
Collage ComputerCollage = new Collage("计算机学院");
Collage InfoEngineerCollage = new Collage("信息工程学院");
//创建计算机学院下的系
ComputerCollage.add(new Department("软件工程系"));
ComputerCollage.add(new Department("网络工程系"));
//创建信息工程学院下的系
InfoEngineerCollage.add(new Department("通信工程系"));
InfoEngineerCollage.add(new Department("信息工程系"));
//将学院加入到学校中
university.add(ComputerCollage);
university.add(InfoEngineerCollage);
university.print();
}
}
//Component 抽象构件
public abstract class Component {
protected String name;
public Component(String name) {
this.name = name;
}
//由子类来实现
protected abstract void print();
}
//University 就是 Composite,可以管理College
public class University extends Component {
//存放的是Collage
private List<Component> components = new ArrayList<>();
public University(String name) {
super(name);
}
protected void add(Component component) {
components.add(component);
}
protected void remove(Component component) {
components.remove(component);
}
@Override //输出University 中包含的学院
protected void print() {
System.out.println("--------"+name+"---------");
//遍历organizationComponents
for (Component component : components) {
component.print();
}
}
}
//Collage 学院 也是 Composite,可以管理department
public class Collage extends Component {
//存放的是department(系)
private List<Component> components = new ArrayList<>();
//构造器
public Collage(String name) {
super(name);
}
protected void add(Component component) {
//将来实际业务中 Collage的add 和 University add不一定相同
components.add(component);
}
protected void remove(Component component) {
components.remove(component);
}
@Override //输出Collage 中包含的系
protected void print() {
System.out.println("--------"+name+"---------");
//遍历organizationComponents
for (Component component : components) {
component.print();
}
}
}// Leaf 树叶构件 系
public class Department extends Component{
public Department(String name) {
super(name);
}
@Override
protected void print() {
System.out.println("--------"+name+"---------");//所在系的名字
}
}
程序运行结果
--------清华大学---------
--------计算机学院---------
--------软件工程系---------
--------网络工程系---------
--------信息工程学院---------
--------通信工程系---------
--------信息工程系---------
3. JDK源码运用
//AbstractMap 相当于Component HashMap相当于Composite Node相当于 Leaf
Map<Integer, String> hashMap = new HashMap<>();
hashMap.put(1, "mm");
hashMap.put(2, "mk");
hashMap.putAll(hashMap);