组合模式(Composite),将对象组合成树形结构以表示’部分-整体‘的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
Component 为组合中的对象声明接口,在适当情况下,实现所有类公共接口的默认行为。声明一个接口用于访问和管理 Component的子部件。
Composite 定义有枝节点行为,用来存储子部件,在 Component 接口中实现与子部件有关的操作。
Leaf 在组合中表示叶节点对象,叶节点没有子节点。
基本代码
组合中的对象声明接口
abstract class Component{protected String name;public Component(String name){this.name = name;}public abstract void add(Component component);public abstract void remove(Component component);public abstract void display(int depth);
}
定义有子节点的对象,实现接口中对子节点的操作方法
class Composite extends Component{// 一个子对象集合用来存储其下属的枝节点和叶节点private ArrayList children = new ArrayList();public Composite(String name){super(name);}// 增加子节点public void add(Component component){children.add(component);}// 移除子节点public void remove(Component component){children.remove(component);}public void display(int depth){//显示其枝节点名称for(var i=0;iitem.display(depth+2);}}
}
叶子节点
class Leaf extends Component{public Leaf(String name){super(name);}public void add(Component component){System.out.println("Cannot add to a leaf.");}public void remove(Component component){System.out.println("Cannot remove from a leaf.");}public void display(int depth){//叶节点的具体显示方法,此处是显示其名称和级别for(var i=0;i
客户端
public class Test {public static void main(String[] args){System.out.println("**********************************************"); System.out.println("《大话设计模式》代码样例");System.out.println(); Composite root = new Composite("root");root.add(new Leaf("Leaf A"));root.add(new Leaf("Leaf B"));Composite comp = new Composite("Composite X");comp.add(new Leaf("Leaf XA"));comp.add(new Leaf("Leaf XB")); root.add(comp);Composite comp2 = new Composite("Composite XY");comp2.add(new Leaf("Leaf XYA"));comp2.add(new Leaf("Leaf XYB"));comp.add(comp2);Leaf leaf = new Leaf("Leaf C");root.add(leaf);Leaf leaf2 = new Leaf("Leaf D");root.add(leaf2);root.remove(leaf2);root.display(1);System.out.println();System.out.println("**********************************************");}
}
显示结果
透明方式,在 Component 中声明所有用来管理子对象的方法,包括 add,remove等。这样做的好处是叶节点和枝节点对于外界没有区别,它们具备完全一致的行为接口。但是叶节点本身不具备 add,remove方法的功能,所以实现它是没有意义的。
安全方式,在 Component 中不去声明 add,remove方法,这样 Leaf 子类就不需要实现它,而是在 Composite 中声明所有用来管理子类对象的方法。这样叶节点和枝节点将不具备有相同的接口。客户端的调用需要做相应的判断。
何时使用组合模式?
当需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时(整体和部分可以被一致对待),就应该考虑使用组合模式。
公司下面有各种部门以及分公司,分公司下面有各种部门以及办事处,办事处下面还有各种部门。
形成了一个树形结构。
在 Company 中定义了 叶子节点和枝节点的行为,忽略了叶子节点(单个对象)和枝节点(组合对象)的不同,统一的看待树形结构中的所有对象。
Company类相当于 Component 类。
HRDepartment 叶子类。
ConcreteCompany 组合类。
公司抽象类
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 lineOfDuty(); //履行职责
}
具体分公司类,树枝节点
class ConcreteCompany extends Company{// 存储下级节点protected ArrayList children = new ArrayList();public ConcreteCompany(String name){super(name);}public void add(Company company){children.add(company);}public void remove(Company company){children.remove(company);}public void display(int depth) { for(var i=0;iitem.display(depth+2);}} //履行职责public void lineOfDuty(){for(Company item : children){item.lineOfDuty();}}
}
叶子节点
//人力资源部,树叶节点
class HRDepartment extends Company{public HRDepartment(String name){super(name);}public void add(Company company){}public void remove(Company company){}public void display(int depth) { for(var i=0;iSystem.out.println(name+" 员工招聘培训管理");}
}
//财务部,树叶节点
class FinanceDepartment extends Company{public FinanceDepartment(String name){super(name);}public void add(Company company){}public void remove(Company company){}public void display(int depth) { for(var i=0;iSystem.out.println(name+" 公司财务收支管理");}
}
客户端
public class Test {public static void main(String[] args){System.out.println("**********************************************"); System.out.println("《大话设计模式》代码样例");System.out.println(); 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 comp2 = new ConcreteCompany("南京办事处");comp2.add(new HRDepartment("南京办事处人力资源部"));comp2.add(new FinanceDepartment("南京办事处财务部"));comp.add(comp2);ConcreteCompany comp3 = new ConcreteCompany("杭州办事处");comp3.add(new HRDepartment("杭州办事处人力资源部"));comp3.add(new FinanceDepartment("杭州办事处财务部"));comp.add(comp3);System.out.println("结构图:");root.display(1);System.out.println("职责:");root.lineOfDuty();System.out.println();System.out.println("**********************************************");}
}
显示结果
组合模式定义了包含基本对象和组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象。用户是不用关心到底是处理一个叶节点还是处理一个组合节点,组合模式可以让客户端一致的使用组合节点和叶节点,不用做任何区分。