组合模式(Composite Pattern)
Compose objects into tree structures to represent part-whole hierarchies.Composite lets clients treat individual objects and compositions of objects uniformly.
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使用户对单个对象和组合对象的使用具有一致性。
组合模式的三个角色
:
- 抽象构件(Component)角色:定义参加组合对象的共有方法和属性
- 叶子构件(Leaf)角色:叶子对象,实现抽象构件角色,低下没有任何分支,定义参加组合的原始对象的行为(如:员工类就为叶子对象,可在此类中定义员工的职位)
- 树枝构件(Composite)角色:该对象参与组合,但其下还有分支或者叶子构件对象,实现抽象构件角色(如:总公司,分公司等)
优点:
- 组合模式中包含个体对象和组合对象,并形成树形结构,使用户可以方便地处理个体对象和组合对象。
- 组合对象和个体对象实现了相同的接口,用户一般无须区分个体对象和组合对象。
- 当增加新的Composite节点和Leaf节点时,用户的重要代码不需要做出修改。
在抽象构件角色中,会将所有树枝节点要用到的方法抽象出来,但这些方法在叶子构件中并不会去重写,这种方式叫做透明方式,也就是说在抽象类中定义了抽象方法,无论其子类用不用到该抽象方法,都将具备此方法,尽管实现该方法是没有意义的,这样做的好处是其叶子节点和树枝节点对外界来看没有区别,因为都实现于同一个接口。
与透明方式相对的,安全方式,也就是子类中不用的方法,接口中就不声明,这样的方式在组合模式,由于得在树枝构件中声明所有用来管理子节点的方法,所以(为方便以后的扩展)得重建一个接口以完成这些方法的抽象。这将使树枝与树叶不具有相同的接口,客户端将需要做出相应的判断。
以一个公司管理系统为列:
import java.util.ArrayList;
import java.util.List;
public class CompositeModel {
public static void main(String[] args) {
//先创建一个总公司以及总公司下的所有部门
ConcreteCompany root = new ConcreteCompany("北京总公司");
root.add(new HRDepartment("总公司人力资源部"));
root.add(new CWDepartment("总公司财务部"));
//第一个分公司以及该公司下的所有部门
ConcreteCompany company1 = new ConcreteCompany("川南分公司");
company1.add(new HRDepartment("川南分公司人力资源部"));
company1.add(new CWDepartment("川南分公司财务部"));
root.add(company1);
//第二个分公司以及该公司下的所有部门
ConcreteCompany company2 = new ConcreteCompany("杭州分公司");
company2.add(new HRDepartment("杭州分公司人力资源部"));
company2.add(new CWDepartment("杭州分公司财务部"));
root.add(company2);
//显示
System.out.println("公司结构:");
root.display(0);
System.out.println("\n各部门职责:");
root.duty();
}
}
//公司抽象类(不能是接口,否则不能定义构造方法)
abstract class Company {
protected String name;
public Company(String name) {
this.name = name;
}
public abstract void add(Company company);
public abstract void remove(Company company);
public abstract void display(int depth);// 树的深度(总公司的下属阶层层数)
public abstract void duty();// 不同部门需要履行不同的职责
}
//具体公司类(树枝节点)
class ConcreteCompany extends Company {
// List保存每一个树枝节点下的子结点
private List<Company> children = new ArrayList<Company>();
public ConcreteCompany(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override //添加树分支
public void add(Company company) {
children.add(company);
}
@Override //删除树分支
public void remove(Company company) {
children.remove(company);
}
@Override // 遍历树枝所有分支(递归)
public void display(int depth) {
//先输出本节点
System.out.println(depth + name);
for (Company c : children) {
c.display(depth + 1);
}
}
@Override //递归遍历该公司下所有部门分支的职责
public void duty() {
for (Company c : children) {
c.duty();
}
}
}
//人力资源部类(树叶节点)
class HRDepartment extends Company {
public HRDepartment(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void add(Company company) {
}
@Override
public void remove(Company company) {
}
@Override //展示该部门的名称
public void display(int depth) {
System.out.println(depth + name);
}
@Override //该部门的职责
public void duty() {
System.out.println(name + "\t员工招聘培训管理");
}
}
//财务部
class CWDepartment extends Company {
public CWDepartment(String name) {
super(name);
}
@Override
public void add(Company company) {
}
@Override
public void remove(Company company) {
}
@Override //展示该部门的名称
public void display(int depth) {
System.out.println(depth + name);
}
@Override //该部门的职责
public void duty() {
System.out.println(name + "\t公司财务收支管理");
}
}
运行结果:
公司结构:
0北京总公司
1总公司人力资源部
1总公司财务部
1川南分公司
2川南分公司人力资源部
2川南分公司财务部
1杭州分公司
2杭州分公司人力资源部
2杭州分公司财务部
各部门职责:
总公司人力资源部 员工招聘培训管理
总公司财务部 公司财务收支管理
川南分公司人力资源部 员工招聘培训管理
川南分公司财务部 公司财务收支管理
杭州分公司人力资源部 员工招聘培训管理
杭州分公司财务部 公司财务收支管理