1. 组合模式
1.1 简介
Composite模式,即组合模式,又叫部分整体模式。Composite模式将对象以树形结构组织起来,以达成“部分-整体” 的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
Composite模式很容易联想到树形结构图。组合体内这些对象都有共同接口,当组合体一个对象的方法被调用执行时,Composite将遍历(Iterator)整个树形结构,寻找同样包含这个方法的对象并实现调用执行,牵一动百。所以Composite模式使用到Iterator模式,和Chain of Responsibility模式类似。
1.2 结构
Composite模式uml:
Composite模式角色:
- Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。
- Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。
- Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。
2. Composite模式示例
我们以公司和公司下各部门为例,一个公司一般会包括hr部门、业务部门、财务部门和法务部门,各部门承担不同职责各司其职。公司即是Composite,公司下各部门则是Leaf,公司可以增加删除部门,同时对各部门的工作进行指导。
Component(抽象公司):
public abstract class AbstractCompany {
protected String name;
public AbstractCompany(String name) {
this.name = name;
}
public boolean add(AbstractCompany company);
public boolean remove(AbstractCompany company);
public void display(int depth);
public void LineOfDuty();
}
google公司:
public class Google extends AbstractCompany {
public Google(String name) {
super(name);
}
private List<AbstractCompany> children = new ArrayList<>();
public boolean add(AbstractCompany company) {
return children.add(company);
}
public boolean remove(AbstractCompany company) {
return children.remove(company);
}
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb.toString() + name);
//递归调用子节点
for (AbstractCompany child : children) {
child.display(depth + 2);
}
}
public void LineOfDuty() {
for (AbstractCompany child : children) {
child.LineOfDuty();
}
}
}
HR部门:
public class HRDepartment extends AbstractCompany {
public HRDepartment(String name) {
super(name);
}
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb.toString() + name);
}
public void LineOfDuty() {
System.out.println(name + ":员工招聘培训管理");
}
}
业务部门:
public class BusinessDepartment extends AbstractCompany {
public BusinessDepartment(String name) {
super(name);
}
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb.toString() + name);
}
public void LineOfDuty() {
System.out.println(name + ":员工业务分配及执行");
}
}
法务部门:
public class LawDepartment extends AbstractCompany {
public LawDepartment(String name) {
super(name);
}
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb.toString() + name);
}
public void LineOfDuty() {
System.out.println(name + ":公司法律事务处理");
}
}
财务部门:
public class FinanceDepartment extends AbstractCompany {
public FinanceDepartment(String name) {
super(name);
}
public void display(int depth) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < depth; i++) {
sb.append("-");
}
System.out.println(sb.toString() + name);
}
public void LineOfDuty() {
System.out.println(name + ":公司员工工资及业务资金结算");
}
}
客户端调用:
public static void main(String[] args) {
AbstractCompany google = new Google("Google");
AbstractCompany hr = new HRDepartment("hr");
AbstractCompany business = new BusinessDepartment("business");
AbstractCompany law = new LawDepartment("law");
AbstractCompany finance = new FinanceDepartment("finance");
google.add(hr);
google.add(business);
google.add(law);
google.add(finance);
google.display(1);
google.LineOfDuty();
}
3. Composite模式总结
Composite模式最显而易见的应用即是文件树,目录即是Composite,文件即是Leaf。包括以前使用的“容器+内容”,其实是通过组合模式实现的,组合模式保证了容器和内容的一致性,容器里面可以套容器,也可以放内容。
适用场景:
- 想表示对象的整体与部分的层次结构时
- 当用户不关心使用的是组合对象还是单个对象时(这时用户的意图应该是使用他直接或间接手下的所有单个对象的相关行为,但他只会对他直接手下下命令)
组合模式特点:
- 部分可以被组合成整体,整体也可以被组合成更大的整体。非叶节点中存储的子节点即可以有叶节点,也可以有非叶节点。
- 用户可以一致的使用组合对象(非叶节点)和单个对象(叶节点)。(当使用组合对象非增- 删改查行为时,会自动的递归调用组合对象下的所有叶节点的对应行为)
- 可以很容易的添加或删除组件
- 要求较高的抽象性,如果节点和叶子有很多差异性的话,比如很多方法和属性都不一样,难以实现组合模式