1 定义
组合模式(Composite Pattern),又叫部分整体模式,属于结构型设计模式,它主要用于将一组相似的对象作为一个单一对象来看待,再依据树形结构来组合对象,用来表示部分以及整体层次,使得调用者可以使用一致的方法操作单个对象或组合对象。例如现实场景中,一个公司里面包含了人事部、技术部、业务部和分公司等,而分公司里的组织结构也同样具有人事部、技术部、业务部等部门。总公司部门和分公司部门都可以理解为属于公司统一管理,是公司的部门或叫旗下部门,这其实就是整体与部分可以被一致对待的表现。
2 实现
组合模式一般包含3个角色,分别是:
- 组合部件(Component),就是叶子和合成部件的抽象类,用于定义各个叶子节点对象的共同行为以及子对象的增加和删除行为。例如上述定义举例的公司统称。
- 叶子节点(Leaf),就是组合表示中的子节点,它没有子类,它需要实现各自的职责行为。例如上述定义举例的人事部、技术部等。
- 合成部件(Composite),就是用来存储子部件的容器,它需要实现了枝节点的增加和删除行为。例如上述定义举例的分公司。
在实现方式上,组合模式可分为透明方式和安全方式,它们的主要区别在于组合部件中:
- 透明方式:在组合部件中声明了所有用来管理子对象增加和删除行为,使叶子节点中也同样需要实现其增加和删除方法,虽然这样实现本身并无意义,但是好处在于叶子节点和枝节点对于外界而言是没有区别的,它们具备完全一致的行为接口。
- 安全方式:在组合部件中不声明了用来管理子对象增加和删除行为,那么叶子节点自然不需要去实现无意义的增加和删除方法,合成部件另外去实现对象的增加和删除行为。由于这样不够透明,所以树叶和树枝将不具有相同的接口,所以在使用上需要做相应的判断。
2.1 透明方式的组合
组合部件类,它是公司的统称和对象共同行为、子对象增加删除行为的定义:
public abstract class Company {
protected String mName;
public Company(String name) {
mName = name;
}
public abstract void action();
public abstract void add(Company company);
public abstract void remove(Company company);
}
叶子节点类,它继承于组合部件类,是具体的部门:
public class TechnologyDepartment extends Company {
public TechnologyDepartment(String name) {
super(name);
}
@Override
public void action() {
System.out.println("我是" + mName + "负责技术攻关");
}
@Override
public void add(Company company) {
}
@Override
public void remove(Company company) {
}
}
public class SalesDepartment extends Company {
public SalesDepartment(String name) {
super(name);
}
@Override
public void action() {
System.out.println("我是" + mName + "负责业务工作");
}
@Override
public void add(Company company) {
}
@Override
public void remove(Company company) {
}
}
合成部件类,它也继承于组合部件类,它可以是总公司,也可以是分公司:
public class ConcreteCompany extends Company {
private List<Company> mCompaynList = new ArrayList<>();
public ConcreteCompany(String name) {
super(name);
}
@Override
public void action() {
for (Company company: mCompaynList) {
company.action();
}
}
@Override
public void add(Company company) {
mCompaynList.add(company);
}
@Override
public void remove(Company company) {
mCompaynList.remove(company);
}
}
客户端:
Company rootCompany = new ConcreteCompany("总公司");
rootCompany.add(new TechnologyDepartment("总公司技术部"));
rootCompany.add(new SalesDepartment("总公司销售部"));
Company branchCompany = new ConcreteCompany("分公司");
branchCompany.add(new TechnologyDepartment("分公司技术部"));
branchCompany.add(new SalesDepartment("分公司销售部"));
rootCompany.add(branchCompany);
rootCompany.action();
输出结果:
我是总公司技术部负责技术攻关
我是总公司销售部负责业务工作
我是分公司技术部负责技术攻关
我是分公司销售部负责业务工作
2.2 安全方式的组合
组合部件类,它是公司的统称,这里仅声明对象共同行为:
public abstract class Company {
protected String mName;
public Company(String name) {
mName = name;
}
protected abstract void action();
}
单独声明子对象增加删除行为的定义的接口:
public interface INode {
void add(Company company);
void remove(Company company);
}
叶子节点类,它继承于组合部件类,是具体的部门:
public class TechnologyDepartment extends Company {
public TechnologyDepartment(String name) {
super(name);
}
@Override
protected void action() {
System.out.println("我是" + mName + "负责技术攻关");
}
}
public class SalesDepartment extends Company {
public SalesDepartment(String name) {
super(name);
}
@Override
protected void action() {
System.out.println("我是" + mName + "负责业务工作");
}
}
合成部件类,它也继承于组合部件类,它可以是总公司,也可以是分公司:
public class ConcreteCompany extends Company implements INode {
private List<Company> mCompaynList = new ArrayList<>();
public ConcreteCompany(String name) {
super(name);
}
@Override
public void add(Company company) {
mCompaynList.add(company);
}
@Override
public void remove(Company company) {
mCompaynList.remove(company);
}
@Override
public void action() {
for (Company company: mCompaynList) {
company.action();
}
}
}
客户端:
ConcreteCompany rootCompany = new ConcreteCompany("总公司");
rootCompany.add(new TechnologyDepartment("总公司技术部"));
rootCompany.add(new SalesDepartment("总公司销售部"));
ConcreteCompany branchCompany = new ConcreteCompany("分公司");
branchCompany.add(new TechnologyDepartment("分公司技术部"));
branchCompany.add(new SalesDepartment("分公司销售部"));
rootCompany.add(branchCompany);
rootCompany.action();
输出结果:
我是总公司技术部负责技术攻关
我是总公司销售部负责业务工作
我是分公司技术部负责技术攻关
我是分公司销售部负责业务工作
3 总结
组合模式就是让调用者可以一致地使用组合结构和单个对象。在需求中体现部分与整体层次结构时,以及希望调用者可以忽略组合对象与单个对象的不同,统一使用组合结构中的所有对象时就应该考虑使用组合模式。它可以让调用者无需关心处理的对象是单个还是容器,当有新的部件时很容易就可添加进来,但同时也使对象关系复杂化,调用者需花更多时间来理解类之间的层次关系。