组合模式(Composite Pattern)
基本介绍
- 组合模式(Composite Pattern),又叫部分整体模式,把部分和整体的关系用树形结构来表示,从而使客户端对单个对象和组合对象的访问具有一致性,可以使用统一的方式处理部分对象和整体对象。
- 组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
UML原理类图
角色及职责分析
- 抽象构件(Component)角色: 定义了叶子和容器构件的共同点。这是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理Component 子部件, Component 可以是抽象类或者接口。
- 叶子(Leaf)构件角色:无子节点
- 容器(Composite)构件角色: 有容器特征, 用于存储子部件。在 Component 接口中实现 子部件的相关操作,比如增加(add), 删除。
工作流程
- 组合模式为处理树形结构提供了完美的解决方案,描述了如何将容器和叶子进行递归组合,使得用户在使用时可以一致性的对待容器和叶子。
- 当容器对象的指定方法被调用时,将遍历整个树形结构,寻找也包含这个方法的成员,并调用执行。其中,使用了递归调用的机制对整个结构进行处理。
开发中的应用场景:
- 操作系统的资源管理器
- GUI中的容器层次图
- XML文件解析
- OA系统中,组织结构的处理
- Junit单元测试框架
• 底层设计就是典型的组合模式,TestCase(叶子)、TestUnite(容器)、Test接口(抽象)
实例分析
编写程序展示一个学校院系结构:需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院, 一个学院有多个系。如图:
传统方式
分析
- 将学院看做是学校的子类,系是学院的子类,这样实际上是站在组织大小来进行分层次的
- 实际上我们的要求是 :在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系, 因此这种方案,不能很好实现的管理的操作,比如对学院、系的添加,删除,遍历等
改进
把学校、院、系都看做是组织结构,他们之间没有继承的关系,而是一个树形结构,可以更好的实现管理操作。 => 组合模式
组合模式
UML类图
代码实现
抽象构件(Component)角色
public interface AbstractOrganization {
/**
* 打印组织名称
*/
void print ();
}
容器(Composite)构件角色
这里是三层树状结构,所以学校和学院都是容器。
学校
class University implements AbstractOrganization {
private String name;
/** 定义容器 */
List<AbstractOrganization> organizations = new ArrayList<>();
public University ( String name ) {
this.name = name;
}
/*
对学院进行管理
*/
protected void add ( AbstractOrganization organization ) {
organizations.add(organization);
}
protected void remove ( AbstractOrganization organization ) {
organizations.remove(organization);
}
public String getName () {
return name;
}
@Override
public void print () {
System.out.println("--------------" + getName() + "--------------");
for (AbstractOrganization organization : organizations) {
organization.print();
}
}
}
学院
class College implements AbstractOrganization {
private String name;
List<AbstractOrganization> organizations = new ArrayList<>();
public College ( String name ) {
this.name = name;
}
protected void add ( AbstractOrganization organization ) {
organizations.add(organization);
}
protected void remove ( AbstractOrganization organization ) {
organizations.remove(organization);
}
public String getName () {
return name;
}
@Override
public void print () {
System.out.println("--------------" + getName() + "--------------");
for (AbstractOrganization organization : organizations) {
organization.print();
}
}
}
叶子(Leaf)构件角色
专业是最小节点,所以不需要直接进行增删操作,无非定义容器。
class Department implements AbstractOrganization {
private String name;
public Department ( String name ) {
this.name = name;
}
public String getName () {
return name;
}
@Override
public void print () {
System.out.println(getName());
}
}
客户端调用
public class Client {
public static void main(String[] args) {
//从大到小创建对象
//学校
University university = new University("清华大学");
//学院
College computerCollege = new College("计算机学院");
College infoEngineercollege = new College("信息工程学院");
//专业
computerCollege.add(new Department("软件工程"));
computerCollege.add(new Department("网络工程"));
computerCollege.add(new Department("计算机科学与技术"));
infoEngineercollege.add(new Department("通信工程"));
infoEngineercollege.add(new Department("信息工程"));
//将学院加入到学校
university.add(computerCollege);
university.add(infoEngineercollege);
System.out.println("--打印大学信息--");
university.print();
System.out.println("--打印学院信息--");
infoEngineercollege.print();
}
}
结果
--打印大学信息--
--------------清华大学--------------
--------------计算机学院--------------
软件工程
网络工程
计算机科学与技术
--------------信息工程学院--------------
通信工程
信息工程
--打印学院信息--
--------------信息工程学院--------------
通信工程
信息工程
组合模式的注意事项和细节
优点
- 简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子的问题。
- 具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系,客户端不用做出任何改动.
- 方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点或者叶子从而创建出复杂的树形结构
- 需要遍历组织机构,或者处理的对象具有树形结构时, 非常适合使用组合模式.
缺点
- 要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,不适合使用组合模式。