组合模式
定义
将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
UML
对象说明
Component
:为组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component的子部件。 Leaf
:在组合结点中表示叶结点对象,叶结点中没有子节点。 Composite
:定义有枝结点的行为,用来存储子部件,在Composite
接口中实现与子部件有关的操作,如增加和删除操作。 client
:通过Component
接口操作组合部件的对象。
组合模式中的两种方式的说明
透明模式:当我们的Leaf
类中是直接继承Component
时,那么Leaf
里面也是存在增加和删除的操作方式,但是实际情况是Leaf
类里面是不应该存在增加和删除的方法的。这种方式称为透明方式。也就是在Component
中声明所有用来管理子对象的方法,其中包括add、remove方法,这样实现Component
接口的所有子类都具备了add和remove方法,这样做的好处是叶结点和枝结点对于外界没有区别,他们具备完全一致的行为接口。但是我们发现实现在Leaf
类中实现add和remove方法是没有意义的。
安全模式:解决掉上面Leaf
结点中不想实现add和remove方法的问题。安全模式就是在Component
接口中不去申明add和remove方法,那么在Leaf
中就不需要去实现这两个方法,而是在Component
声明所有用来管理子类对象的方法,这样做就不会存在刚才出现的问题。但是由于不透明,所以树叶和树枝类将不再具有相同的接口。客户端的调用需要做相应的判断,带来了不便。
Demo
本示例主要是讲解公司的管理系统的建立,主要是使用组合模式来剖析公司的组成状态。
首先画出公司管理系统的UML
基类:定义公司所具有的公共属性
abstract public class BaseCompany { protected String name; public BaseCompany(String name) { this.name = name; } /** * 增加子公司 * @param company :增加子公司 * */ public abstract void add(BaseCompany company); /** * 移除子公司 * @param company :移除具体的公司 * */ public abstract void removeCompany(BaseCompany company); /** * 显示 * @param depth :显示深度 * */ public abstract void display(int depth); /** * 履行职责 * */ public abstract void lineOfDuty(); }
具体的公司:
public class ConcreteCompany extends BaseCompany{ private List<BaseCompany> companies=new ArrayList<>(); public ConcreteCompany(String name) { super(name); } @Override public void add(BaseCompany company) { companies.add(company); } @Override public void removeCompany(BaseCompany company) { companies.remove(company); } @Override public void display(int depth) { System.out.println(depth+"-"+this.name); for(BaseCompany company:companies){ company.display(depth+2); } } @Override public void lineOfDuty() { for(BaseCompany company :companies){ company.lineOfDuty(); } } }
两个部门
public class FinanceDepartment extends BaseCompany { public FinanceDepartment(String name) { super(name); } @Override public void add(BaseCompany company) { } @Override public void removeCompany(BaseCompany company) { } @Override public void display(int depth) { System.out.println(depth+"-"+this.name); } @Override public void lineOfDuty() { System.out.println("公司财务收支管理"); } }
public class HRDepartment extends BaseCompany{ public HRDepartment(String name) { super(name); } @Override public void add(BaseCompany company) { } @Override public void removeCompany(BaseCompany company) { } @Override public void display(int depth) { System.out.println(depth+"-"+this.name); } @Override public void lineOfDuty() { System.out.println("招聘员工"); } }
客户端
public class Client { public static void main(String[] args) { ConcreteCompany root=new ConcreteCompany("北京总公司"); root.add(new HRDepartment("总公司人力资源部")); root.add(new FinanceDepartment("总公司财务部")); ConcreteCompany comp=new ConcreteCompany("上海华东分公司"); comp.add(new HRDepartment("华东分公司人力资源部")); comp.add(new FinanceDepartment("华东分公司财务部")); //将华东分公司划到总公司旗下 root.add(comp); ConcreteCompany comp1=new ConcreteCompany("南京办事处"); comp.add(new HRDepartment("南京办事处人力资源部")); comp.add(new FinanceDepartment("南京办事处财务部")); //将南京办事处划到上海华东公司旗下 comp.add(comp1); System.out.println("结构图"); root.display(1); System.out.println("职责"); root.lineOfDuty(); } }
组合模式小结
当我们发现需求中是体现部分与整体层次的结构时,以及我们希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,那么就是应该考虑使用组合模式。
组合模式的好处:基本对象可以组合成更为复杂的组合对象,而这个组合对象又可以被组合,这样就是不断的递归下去,客户端代码中,任何使用基本对象的地方都可以使用组合对象。
同样的,组合模式就是让一个客户可以一致的使用组合结构和单个对象。