定义
组合模式(Composite Pattern):组合多个对象形成树形结构以表示具有“整体—部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“整体—部分”(Part-Whole)模式,它是一种对象结构型模式。
通俗理解
生活中有许多树型结构的东西,例如一家公司的员工关系,由董事长管理CEO、COO、CTO、CFO等等,又由CTO管理研发部门,测试部门,运维部门等等,每一个部门也有部门老大,部门当中也有项目组,项目组中有组长,组长还管理着组员;文件夹的目录也是这样的一个结构,文件夹中有文件夹,也有文件,他们按照树型的结构一直往下延伸。
就用员工组织做例子。按一般的想法设计这一个树形的系统,我们会认为,部门是一个是一个对象,而员工是另外一个对象。对于部门而言,我们能够显示他的基本信息,能够添加部门(子部门)、添加部门(子部门)、添加员工、删除员工,而对于个人而言,我们只能够显示基本信息,对于添加员工和删除员工的操作是不存在的。
把他们割裂开来会出现什么问题?第一:访问部门和访问个人需要区分两个不同的接口,而显示基本信息的是部门和个人都通用的方法却没有提供出来。第二:造成部门会很复杂,在部门当中,需要写添加部门的方法,同时也需要写添加员工的方法;第三:不方便扩展,如果我部门是具有不同的性质的,例如在信息部门中添加研发部门,运维部门等,研发和运维有不同的性质,那么我们需要在信息部门当中改相关的方法,这就违背了开闭原则。
换一个想法,把个人和部门都看成是一个一样的东西,部门和个人都有显示信息的方法,那么我们就把他们提取出来,做成公用的方法。而关于添加个人的方法,由于个人不可能再添加了,所以当用户调用这个方法的时候,就抛出异常。这样的设计,就能够整体对待部门和个人了。
示例
渣渣程序
员工信息
public class Staff {
private String name;
public Staff(String name) {
this.name = name;
}
public void info() {
System.out.println(name);
}
}
部门
public class Department {
public String name;
public List<Staff> staffList = new ArrayList<>();
public List<Department> departmentList = new ArrayList<>();
public Department(String name) {
this.name = name;
}
public void addStaff(Staff staff) {
staffList.add(staff);
}
public void removeStaff(Staff staff) {
staffList.remove(staff);
}
public void addDepartment(Department department) {
departmentList.add(department);
}
public void removeDepartment(Department department) {
departmentList.remove(department);
}
public void info() {
System.out.println(name);
}
}
入口
public class Main {
public static void main(String[] args) {
Department infoDep = new Department("信息部门");
Department devDep = new Department("研发部门");
Department opsDep = new Department("运维部门");
infoDep.addDepartment(devDep);
infoDep.addDepartment(opsDep);
Staff ccc = new Staff("ccc");
Staff ddd = new Staff("ddd");
devDep.addStaff(ccc);
devDep.addStaff(ddd);
Staff eee = new Staff("eee");
Staff fff = new Staff("fff");
opsDep.addStaff(eee);
opsDep.addStaff(fff);
new Main().info(infoDep);
}
public void info(Department department) {
department.info();
for (Staff staff : department.staffList) {
staff.info();
}
for(Department department1 : department.departmentList) {
info(department1);
}
}
}
/**
* 信息部门
* 研发部门
* ccc
* ddd
* 运维部门
* eee
* fff
*/
优化
类图
程序
部门和员工的统一抽象类
public abstract class DepartmentStaff {
public abstract void info();
public boolean isDepartment() {
return false;
}
public void add(DepartmentStaff departmentStaff) {
System.out.println("系统发生错误");
}
public void remove(DepartmentStaff departmentStaff) {
System.out.println("系统发生错误");
}
public List<DepartmentStaff> getChild() {
System.out.println("系统发生错误");
return null;
}
}
部门
public class Department extends DepartmentStaff {
private List<DepartmentStaff> children;
private String name;
public Department(String name) {
this.name = name;
children = new ArrayList<>();
}
@Override
public void info() {
System.out.println("部门:"+name);
for(DepartmentStaff departmentStaff : getChild()) {
departmentStaff.info();
}
}
@Override
public void add(DepartmentStaff departmentStaff) {
getChild().add(departmentStaff);
}
@Override
public void remove(DepartmentStaff departmentStaff) {
getChild().remove(departmentStaff);
}
@Override
public List<DepartmentStaff> getChild() {
return children;
}
public void setChildren(List<DepartmentStaff> children) {
this.children = children;
}
}
员工
public class Staff extends DepartmentStaff {
private String name;
public Staff(String name) {
this.name = name;
}
@Override
public void info() {
System.out.println("员工:"+name);
}
}
入口
public class Main {
public static void main(String[] args) {
DepartmentStaff d1 = new Department("d1");
DepartmentStaff d1_1 = new Department("d1_1");
DepartmentStaff s1 = new Staff("s1");
d1_1.add(s1);
d1.add(d1_1);
d1.info();
}
}
//部门:d1
//部门:d1_1
//员工:s1
优点
- 整体和部分都是一样的,调用方不用关心处理的是整体还是部分;
- 节点层次容易添加。
缺点
- 直接使用了实现,违反依赖倒置原则。
应用场景
- 整体和部分希望一致对待的;
- 维护整体与部分的关系的;
程序
吐槽
一脸懵逼