23种设计模式之组合模式
参考资料
- Java设计模式:23种设计模式全面解析(超级详细)
- 韩顺平老师的Java设计模式(图解+框架源码剖析)
- 秦小波老师的《设计模式之禅》
下文如有错漏之处,敬请指正
一、简介
定义
将对象组合成树形结构以表示“部分与整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
特点
- 组合模式是一种结构型模式。
- 组合模式能让客户端以一致的方式处理单独对象和组合对象。
通用类图
组合模式的主要角色:
-
Component
根节点
定义了节点要使用的共有方法和属性,可以是一个抽象类、接口或具体类(例如组织)。
-
Leaf
叶子节点
继承Component(例如学院下的系(专业)),其下再也没有其他的分支,也就是遍历的最小单位。
-
Composite
树枝节点
继承并组合Component,通过组合树枝节点和叶子节点,形成一个树形结构。
优点
- 组合模式屏蔽了对象系统的层次差异性(树节点和叶子节点为不同类型),使得客户端可以忽略层次间的差异,使用一致的行为控制不同层次。
- 组合模式可以很方便地增加 树枝节点 和 叶子节点 对象,只要找到它的父节点就成,符合开闭原则。
缺点
- 如果类系统(树形结构)过于庞大,虽然对不同层次都提供一致性操作,但客户端仍需花费时间理清类之间的层次关系。
- 组合模式在具体实现上违背了设计模式 接口隔离原则 或 依赖倒置原则。
应用场景
- 要处理的对象可以生成一棵树形结构,且对树上的节点和叶子节点能进行一致的操作。
- 维护和展示部分与整体关系的场景,如树形菜单、文件和文件夹管理。
二、组合模式
需求:在一个页面上显示出学校的院系组成(一个学校有多个学院,一个学院有多个系)
Component:
package composite;
public abstract class OrganizationComponent {
// 组织名称
private String name;
// 组织描述
private String desc;
public OrganizationComponent() {
}
public OrganizationComponent(String name, String desc) {
this.name = name;
this.desc = desc;
}
// 增加一个叶子节点或树枝节点
protected void add(OrganizationComponent organizationComponent) {
// 默认实现,需要子类重写
throw new UnsupportedOperationException();
}
// 删除一个叶子节点或树枝节点
protected void remove(OrganizationComponent organizationComponent) {
// 默认实现,需要子类重写
throw new UnsupportedOperationException();
}
// 遍历根节点,由子类实现
protected abstract void print();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
Composite:
package composite;
import java.util.ArrayList;
import java.util.List;
public class UniversityComposite extends OrganizationComponent {
// 组合容器(组合学院)
List<OrganizationComponent> colleges = new ArrayList<>();
public UniversityComposite(String name, String desc) {
super(name, desc);
}
@Override
protected void add(OrganizationComponent organizationComponent) {
colleges.add(organizationComponent);
}
@Override
protected void remove(OrganizationComponent organizationComponent) {
colleges.remove(organizationComponent);
}
@Override
protected void print() {
System.out.println("================" + super.getName() + "================");
for (OrganizationComponent college : colleges) {
college.print();
}
}
}
package composite;
import java.util.ArrayList;
import java.util.List;
public class CollegeComposite extends OrganizationComponent {
// 组合容器(组合系)
List<OrganizationComponent> departments = new ArrayList<>();
public CollegeComposite(String name, String desc) {
super(name, desc);
}
@Override
protected void add(OrganizationComponent organizationComponent) {
departments.add(organizationComponent);
}
@Override
protected void remove(OrganizationComponent organizationComponent) {
departments.remove(organizationComponent);
}
@Override
protected void print() {
System.out.println("================" + super.getName() + "================");
for (OrganizationComponent department : departments) {
department.print();
}
}
}
Leaf:
package composite;
public class DepartmentLeaf extends OrganizationComponent {
public DepartmentLeaf(String name, String desc) {
super(name, desc);
}
@Override
protected void print() {
System.out.println(super.getName());
}
}
Client:
package composite;
public class Client {
public static void main(String[] args) {
// 创建学校
OrganizationComponent university = new UniversityComposite("XX大学", "双一流大学");
// 创建学院
OrganizationComponent computerCollege = new CollegeComposite("计算机学院", "计算机学院");
OrganizationComponent infoCollege = new CollegeComposite("信息工程学院", "信息工程学院");
// 为学校添加学院
university.add(computerCollege);
university.add(infoCollege);
// 为学院添加系(专业)
computerCollege.add(new DepartmentLeaf("软件工程", "软件工程专业"));
computerCollege.add(new DepartmentLeaf("网络工程", "网络工程专业"));
computerCollege.add(new DepartmentLeaf("计算机科学与技术", "计算机科学与技术专业"));
infoCollege.add(new DepartmentLeaf("通信工程", "通信工程专业"));
infoCollege.add(new DepartmentLeaf("信息程", "信息工程专业"));
// 打印学校组织结构图
university.print();
// 打印学院组织结构图
computerCollege.print();
infoCollege.print();
/**
* 输出结果:
* ================XX大学================
* ================计算机学院================
* 软件工程
* 网络工程
* 计算机科学与技术
* ================信息工程学院================
* 通信工程
* 信息程
* ================计算机学院================
* 软件工程
* 网络工程
* 计算机科学与技术
* ================信息工程学院================
* 通信工程
* 信息程
*
*/
}
}
三、总结
组合模式可以使客户端对部分与整体的操作具有一致性。只要是树形结构或者体现局部和整体的关系的时候,可以考虑一下组合模式。