组合模式--分公司=一部门
组合模式:将对象组合成树形接口以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
为什么Leaf类中也有add和remove,树叶不是不可以再长分支吗?
是的,这种方式叫做透明方式,也就是说在Component中声明所有用来管理子对象的方法啊,其中包括add、remove等。这样实现Component接口的所有子类都具备了add和remove。这样做的好处就是叶节点和枝节点对于外界没有区别,他们具备完全一致的行为接口。但问题也很明显,因为Leaf类本身不具备add()、remve()方法的功能,所以实现它是没有意义的。
如果我不希望Leaf类中用add和remove方法,那么子类的Leaf也就不需要去实现它,而是在Composite声明所有用来管理子类对象的方法,这样做就不会出现刚才提到的问题,不过由于不够透明,所以树叶和树枝将不具有相同的接口,客户端的调用需要做相应的判断,带来了不便。
透明方式,那样就不用做任何判断了。
应用场景:当你发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。
组合模式让客户可以一致地使用组合结构和单个对象。
1 /** 2 * Component为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为。 3 * 声明一个接口用于访问和管理Component的子部件 4 * @author 贤元 5 * 6 */ 7 public abstract class Component { 8 protected String name; 9 public Component(String name){ 10 this.name = name; 11 } 12 13 public abstract void add(Component c); 14 public abstract void remove(Component c); 15 public abstract void display(int depth); 16 }
1 /** 2 * Component定义有枝节点行为,用来存储子部件, 3 * 在Component接口中实现与子部件有关的操作,比如增加add和删除remove 4 * @author 贤元 5 * 6 */ 7 public class Composite extends Component { 8 9 private List<Component> children = new LinkedList<Component>(); 10 11 public Composite(String name) { 12 super(name); 13 // TODO Auto-generated constructor stub 14 } 15 16 @Override 17 public void add(Component c) { 18 children.add(c); 19 } 20 21 @Override 22 public void remove(Component c) { 23 children.remove(c); 24 } 25 26 @Override 27 public void display(int depth) { 28 String str = "";//用于拼接'-',depth表示多少,就拼接多少个'-',用于显示效果 29 for(int i=0;i<depth;i++){ 30 str += "-"; 31 } 32 System.out.println(str+name); 33 34 for(Component component:children){ 35 component.display((depth+2)); 36 } 37 } 38 39 }
1 public class Leaf extends Component{ 2 3 public Leaf(String name) { 4 super(name); 5 // TODO Auto-generated constructor stub 6 } 7 8 /** 9 * 由于叶子没有再增加分支和树叶,所以add和remove实现它没有意义, 10 * 但这样做可以消除叶节点和枝节点对象在抽象层次的区别,他们具备完全一致的接口。 11 */ 12 @Override 13 public void add(Component c) { 14 System.out.println("Cannot add to a leaf"); 15 } 16 17 @Override 18 public void remove(Component c) { 19 System.out.println("Cannot remove from a leaf"); 20 } 21 22 //叶节点的具体方法,此处是显示其名称和级别 23 @Override 24 public void display(int depth) { 25 String str = "";////用于拼接'-',depth表示多少,就拼接多少个'-',用于显示效果 26 for(int i=0;i<depth;i++){ 27 str += "-"; 28 } 29 System.out.println(str+name); 30 } 31 }
1 public class TestClient { 2 public static void main(String[] args) { 3 //生成树根root,根上长出两叶LeafA和LeafB 4 Component root = new Composite("root"); 5 root.add(new Leaf("Leaf A")); 6 root.add(new Leaf("Leaf B")); 7 8 //根上长出分支CompositeX,分支上也有两叶LeafXA和LeafXB 9 Composite comp = new Composite("Composite A"); 10 comp.add(new Leaf("Leaf XA")); 11 comp.add(new Leaf("Leaf XB")); 12 13 root.add(comp); 14 15 //在CompositeX上再长出分支CompositeXY,分支上也有两叶LeafXYA和LeafXYB 16 Composite comp2 = new Composite("Composite XY"); 17 comp2.add(new Leaf("Leaf XYA")); 18 comp2.add(new Leaf("Leaf XYB")); 19 20 comp.add(comp2); 21 22 root.add(new Leaf("Leaf C")); 23 24 //根部又长出两叶LeafC和LeafD,可惜LeafD没长牢,被风吹走了 25 Leaf leaf = new Leaf("Leaf D"); 26 root.add(leaf); 27 root.remove(leaf); 28 29 //显示大树的样子 30 root.display(1); 31 32 } 33 }
打印结果:
-root
---Leaf A
---Leaf B
---Composite A
-----Leaf XA
-----Leaf XB
-----Composite XY
-------Leaf XYA
-------Leaf XYB
---Leaf C
UML图:
一个例子:
组合模式定义了包含人力资源部和财务部这些基本对象和分公司、办事处等组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了。用户不关心到底是处理一个叶节点还是处理一个组合组件,也就用不着为定义组合而写一些选择判断语句了。组合模式让客户可以一致地使用组合结构和单个对象。
只要写一套代码,就可以在不同层次级别中使用,而不用对不同层次的再重复开发一套代码
1 //公司类,抽象类或接口 2 public abstract class Company { 3 protected String name; 4 5 public Company(String name){ 6 this.name = name; 7 } 8 9 public abstract void add(Company c);//增加 10 public abstract void remove(Company c);//移除 11 public abstract void display(int depth);//显示 12 public abstract void lineOfDuty();//履行职责 13 }
1 //具体公司类,实现接口,树枝节点 2 public class ConcreteCompany extends Company { 3 4 private List<Company> children = new LinkedList<Company>(); 5 6 //构造方法 7 public ConcreteCompany(String name) { 8 super(name); 9 } 10 11 @Override 12 public void add(Company c) { 13 children.add(c); 14 } 15 16 @Override 17 public void remove(Company c) { 18 children.remove(c); 19 } 20 21 @Override 22 public void display(int depth) { 23 String str = "";//用于拼接'-',dept等于多少就表示拼接几个'-',用于显示效果 24 for(int i=0;i<depth;i++){ 25 str +="-"; 26 } 27 System.out.println(str+name); 28 29 for(Company component:children){ 30 component.display(depth+2);//递归显示 31 } 32 } 33 34 35 //履行职责 36 @Override 37 public void lineOfDuty() { 38 // TODO Auto-generated method stub 39 for(Company component:children){ 40 component.lineOfDuty(); 41 } 42 } 43 44 }
1 //人力资源部 2 public class HRDepartment extends Company { 3 4 public HRDepartment(String name) { 5 super(name); 6 } 7 8 @Override 9 public void add(Company c) { 10 } 11 12 @Override 13 public void remove(Company c) { 14 } 15 16 @Override 17 public void display(int depth) { 18 String str = "";// 用于拼接'-',dept等于多少就表示拼接几个'-',用于显示效果 19 for (int i = 0; i < depth; i++) { 20 str += "-"; 21 } 22 System.out.println(str + name); 23 } 24 25 // 履行职责 26 @Override 27 public void lineOfDuty() { 28 System.out.println(name + "员工招聘管理培训"); 29 } 30 }
1 //财务部 2 public class FinanceDepartment extends Company { 3 4 public FinanceDepartment(String name) { 5 super(name); 6 } 7 8 @Override 9 public void add(Company c) { 10 } 11 12 @Override 13 public void remove(Company c) { 14 } 15 16 @Override 17 public void display(int depth) { 18 String str = "";//用于拼接'-',dept等于多少就表示拼接几个'-',用于显示效果 19 for(int i=0;i<depth;i++){ 20 str +="-"; 21 } 22 System.out.println(str+name); 23 } 24 25 @Override 26 public void lineOfDuty() { 27 System.out.println(name+"公司财务收支管理"); 28 } 29 30 }
1 //客户端 2 public class TestClient { 3 public static void main(String[] args) { 4 ConcreteCompany root = new ConcreteCompany("北京总公司"); 5 root.add(new HRDepartment("总公司人力资源部")); 6 root.add(new FinanceDepartment("总公司财务部")); 7 8 ConcreteCompany comp = new ConcreteCompany("华东分公司"); 9 comp.add(new HRDepartment("华东分公司人力资源部")); 10 comp.add(new FinanceDepartment("华东分公司财务部")); 11 root.add(comp);//将子公司添加到总公司 12 13 ConcreteCompany comp1 = new ConcreteCompany("南京办事处"); 14 comp1.add(new HRDepartment("南京事处人力资源部")); 15 comp1.add(new FinanceDepartment("南京办事处财务部")); 16 root.add(comp1);//将子公司添加到总公司 17 18 ConcreteCompany comp2 = new ConcreteCompany("杭州办事处"); 19 comp2.add(new HRDepartment("杭州办事处人力资源部")); 20 comp2.add(new FinanceDepartment("杭州办事处财务部")); 21 root.add(comp2);//将子公司添加到总公司 22 23 System.out.println("结构图:"); 24 root.display(1); 25 26 System.out.println("职责:"); 27 root.lineOfDuty(); 28 29 } 30 }
打印结果:
结构图:
-北京总公司
---总公司人力资源部
---总公司财务部
---华东分公司
-----华东分公司人力资源部
-----华东分公司财务部
---南京办事处
-----南京事处人力资源部
-----南京办事处财务部
---杭州办事处
-----杭州办事处人力资源部
-----杭州办事处财务部
职责:
总公司人力资源部员工招聘管理培训
总公司财务部公司财务收支管理
华东分公司人力资源部员工招聘管理培训
华东分公司财务部公司财务收支管理
南京事处人力资源部员工招聘管理培训
南京办事处财务部公司财务收支管理
杭州办事处人力资源部员工招聘管理培训
杭州办事处财务部公司财务收支管理
UML图: