- 组合模式
组合模式又叫部分整体模式,适用于把一组相似的对象当做一个单一的对象进行处理,组合模式是以树形结构来表示部分-整体的层次结构。组合模式是用户可以按照相同的方法去处理单个对象和组合对象。 - 组合式示意图:组合模式在使用上又分为两种,一种是透明组合模式和安全组合模式。类图分别如下:
2.1. 透明组合模式 :抽象的根节点声明了管理叶节点的方法以及业务方法,客户端可以一致对待所有对象。但是由于叶节点不可能管理子节点,如果处理方式不对,容易出错。
2.2. 安全组合模式:抽象根节点只声明了业务方法,具体子节点的管理方法有自己声明。因为叶节点没有管理子节点的方法,相对来说是安全的,这就导致了叶子节点和node节点的结构不一致,因此需要区别对待。
3.组合模式中所包含的角色
- 抽象根节点角色: 可以是接口或者是抽象类,为叶子和node声明结构,在该角色可以定义leaf和node子类所共有的方法,也可以定义管理子节点的方法。
- 叶子节点:遍历的最小单位,其下面就再也没有任何分支
- 树枝节点:非遍历的最小单位,其中可以包含一个或者多个叶节点或树枝节点,可以递归调用叶节点的业务方法。
4.组合模式实例代码
示例代码:
场景:末公司扩大组织结构,新增了多个一级部门和二级部门,假定方便管理,该公司最小部门为二级部门。现在需求是使用组合模式,打印出其所有部门。(这里很明显二级部门是叶子节点,一级部门是树枝节点)
根节点:
public abstract class Department {
/**
* 添加方法
* @param department
*/
abstract void add(Department department);
/**
* 移除方法
* @param department
*/
abstract void remove(Department department);
/**
* 获取子节点
* @return
*/
abstract ArrayList<Department> getChild();
/**
* 打印
*/
abstract void print();
}
树枝节点:
public class FirstDepartment extends Department {
//用于存储叶子节点
ArrayList<Department> departments = new ArrayList<Department>();
private String name;
public FirstDepartment(ArrayList<Department> departments,String name) {
this.departments = departments;
this.name = name;
}
@Override
void add(Department department) {
departments.add(department);
}
@Override
void remove(Department department) {
if (departments.contains(department)){
departments.remove(department);
}else {
System.out.println("不存在该部门,无法移除");
}
}
@Override
ArrayList<Department> getChild() {
return departments;
}
@Override
void print() {
System.out.println("一级部门>>>>"+this.name);
Iterator iterator = departments.iterator();
while (iterator.hasNext()){
((Department)iterator.next()).print();
}
}
}
树叶节点:
public class SecondDepartment extends Department {
private String name;
public SecondDepartment(String name) {
this.name = name;
}
@Override
void add(Department department) {
System.out.println("已经是叶子节点无法添加子节点!");
}
@Override
void remove(Department department) {
System.out.println("已经是叶子节点无法移除子节点!");
}
@Override
ArrayList<Department> getChild() {
System.out.println("已经是叶子节点无多余的子节点!");
return null;
}
@Override
void print() {
System.out.println("叶子节点>>>>>>>>>>"+name);
}
}
测试主方法:
public class Main {
public static void main(String[] args) {
ArrayList hr = new ArrayList();
Department leaf = new SecondDepartment("人力资源业务一部");
Department leaf1 = new SecondDepartment("人力资源业务2部");
hr.add(leaf);
hr.add(leaf1);
Department departmentForHr = new FirstDepartment(hr,"人力资源部");
departmentForHr.print();
ArrayList pmo = new ArrayList();
Department leaf2 = new SecondDepartment("PMO业务一部");
Department leaf3 = new SecondDepartment("PMO业务一部");
pmo.add(leaf2);
pmo.add(leaf3);
Department departmentForPMO = new FirstDepartment(pmo,"PMO");
departmentForHr.print();
}
}
- 组合模式的优缺点
优点:
- 可以清楚的定义树形的复杂对象。表示对象的全部层次或者部分层次
- 可以使用单一的对象,而不必关心处理的对象是叶子节点还是树枝节点,简化客户端代码。
- 便于增加叶子节点和树枝节点,而不需要修改原有代码。
- 通过叶子对象和容器对象的递归组合可以形成复杂的树形机构,但对树形结构的控制却很简单。
缺点:
- 在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
- 难以对容器中的构件类型限制。