组合模式
组合模式又叫部分-整体模式,组合模式将对象组合成树的结构,并且让客户端对单个对象和组合对象的使用能够保持一致,组合模式使用的场景不是非常多,但如果一旦数据满足树形结构,那么使用组合模式将会发挥巨大的作用。
主要角色
Component
组合模式中的“根”
节点,一般定义为接口或者抽象类,定义了其实现类或者子类的共性内容,并且拥有管理和访问其子部分的方法。
Leaf
组合模式中的“叶子”
节点,实现“根”节点定义的方法。
Composite
组合模式中的“子树”
节点,实现“根”节点定义的方法。
案例演示
假设我们有一套针对组织机构处理的业务场景,机构下可以挂子机构,另外有每个机构下又会有员工,因此整个数据模型大概如下:
机构表
机构ID | 上级机构 |
---|---|
1 | 0 |
2 | 1 |
3 | 1 |
4 | 2 |
员工表
员工ID | 所属机构 | 薪资 |
---|---|---|
1 | 1 | 2000 |
2 | 1 | 5000 |
3 | 2 | 3000 |
4 | 3 | 6000 |
5 | 4 | 8000 |
现在我们需要构建机构、员工组织架构图,并计算每个部门下所有员工的薪资综合。
代码实现
公司
公司就相当于Component角色,有id和salary两个字段,并定义了一个统计公司薪资总和的方法。
public abstract class Company {
protected long id;
protected double salary;
public Company(long id) {
this.id = id;
}
public abstract double calculateSalary();
}
机构
机构就相当于Composite角色,内部维护的companies集合,既可以添加companies,也可以添加leaf,也就是机构可以有下级机构,也可以直接挂员工。
public class Org extends Company {
private List<Company> companies = new ArrayList<>();
public Org(long id) {
super(id);
}
@Override
public double calculateSalary() {
double totalSalary = 0;
for (Company company : companies) {
totalSalary += company.calculateSalary();
}
this.salary = totalSalary;
return totalSalary;
}
public void addCompany(Company company) {
companies.add(company);
}
}
员工
员工就相当于leaf角色,直接记录每个员工的薪资即可。
public class Employee extends Company {
private double salary;
public Employee(long id, double salary) {
super(id);
this.salary = salary;
}
@Override
public double calculateSalary() {
return salary;
}
}
测试结果
测试案例:
ID为1的机构,下面分别挂了ID为2、3的两个机构,以及ID为1、2的两个员工。
ID为2的机构,挂了ID为4的机构,以及ID为3的员工。
ID为3的机构,挂了ID为4的员工。
ID为4的机构,挂了ID为5的员工。
public class Main {
public static void main(String[] args) {
test();
}
private static void test() {
Org org1 = new Org(1);
Org org2 = new Org(2);
Org org3 = new Org(3);
Org org4 = new Org(4);
Employee e1 = new Employee(1, 2000);
Employee e2 = new Employee(2, 5000);
Employee e3 = new Employee(3, 3000);
Employee e4 = new Employee(4, 6000);
Employee e5 = new Employee(5, 8000);
org1.addCompany(e1);
org1.addCompany(e2);
org1.addCompany(org2);
org1.addCompany(org3);
org2.addCompany(e3);
org2.addCompany(org4);
org3.addCompany(e4);
org4.addCompany(e5);
System.out.println("org1 totalSalary: " + calculateSalary(org1));
System.out.println("org2 totalSalary: " + calculateSalary(org2));
System.out.println("org3 totalSalary: " + calculateSalary(org3));
System.out.println("org4 totalSalary: " + calculateSalary(org4));
}
private static double calculateSalary(Org org) {
return org.calculateSalary();
}
}
输出结果
org1 totalSalary: 24000.0
org2 totalSalary: 11000.0
org3 totalSalary: 6000.0
org4 totalSalary: 8000.0
总结
通过上面的案例可以体会到,组合模式将机构和员工视为一组对象,其中员工为单个对象,机构为组合对象,把他们统一进行处理,利用树结构的特点,递归处理每个“子树”,简化客户端的操作,解耦了复杂对象的处理过程,同时高层模块调用简单,节点增加自由,易于扩展,不过组合模式只适用于类似树形结构的业务数据,实际应用场景有限。