设计模式 (十二)组合模式(Composite)

树形结构在日常生活中是非常常见的,比如组织机构的这几,软件菜单的设计等,这些属性结构,他们的叶子节点和父节点在行为上基本是一致的。只是在父节点上可能又包含了子节点。这类应用在软件设计中,如果更好的来实现呢?这样我们就引出了下面对于组合模式的简单介绍:

组合模式(Composite)是整体与部分的关系,一个典型的应用就是树型结构,组合模式可以抽象出三种角色,分别为抽象构建角色(Component)、树枝构建角色(Composite)、树叶构建角色(Leaf).

 抽象构件角色Component:它为组合中的对象声明接口,也可以为共有接口实现缺省行为。

树叶构件角色Leaf:在组合中表示叶节点对象——没有子节点,实现抽象构件角色声明的接口。

树枝构件角色Composite:在组合中表示分支节点对象——有子节点,实现抽象构件角色声明的接口;存储子部件。 

下面简单的从原理图来理解这个组合模式:


然后应用到了具体的实力,我简单的举例,比如现在我们的年级,在专业分流之前我们四个班级的,电气6、7、8、9班,然后通过一个Composite类对这四个班级的人数的统计,实例如下:

首先设计的是一个年级接口,定义了一个getCount方法获得这个年级所属班级的人数,从而达到一个一级一级节点的遍历,班级通过实现统一的接口,调用者对单一对象和组合对象的操作具有一致性。

[java] view plaincopy
  1. package com.designpattern.composite;  
  2.   
  3. public interface Grade {  
  4.     public int getCount();  
  5. }  
然后分别写了四个班级的代码:

[java] view plaincopy
  1. package com.designpattern.composite;  
  2.   
  3. public class ElectricalClass6 implements Grade {  
  4.   
  5.     @Override  
  6.     public int getCount() {  
  7.         return 53;  
  8.     }  
  9.   
  10. }  

[java] view plaincopy
  1. package com.designpattern.composite;  
  2.   
  3. public class ElectricalClass7 implements Grade {  
  4.   
  5.     @Override  
  6.     public int getCount() {  
  7.         return 68;  
  8.     }  
  9.   
  10. }  

[java] view plaincopy
  1. package com.designpattern.composite;  
  2.   
  3. public class ElectricalClass8 implements Grade {  
  4.   
  5.     @Override  
  6.     public int getCount() {  
  7.         return 70;  
  8.     }  
  9.   
  10. }  

[java] view plaincopy
  1. package com.designpattern.composite;  
  2.   
  3. public class ElectricalClass9 implements Grade {  
  4.   
  5.     @Override  
  6.     public int getCount() {  
  7.         return 69;  
  8.     }  
  9.   
  10. }  

紧接着写了一个Composite类,也实现这个年级的接口,同时实现年级Grade接口里面声明所有的用来管理子类对象的方法,以达到对年级Grade接口的最大化。目的就是为了使客户看来在接口层次上树叶和分支没有区别,达到一个对于实现的透明度。

[java] view plaincopy
  1. package com.designpattern.composite;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.List;  
  5.   
  6. public class Composite implements Grade {  
  7.   
  8.     private List list = new ArrayList();  
  9.   
  10.     public Composite add(Grade grade) {  
  11.         list.add(grade);  
  12.         return this;  
  13.     }  
  14.   
  15.     public Grade getChild(int i) {  
  16.         return (Grade) list.get(i);  
  17.     }  
  18.   
  19.     @Override  
  20.     public int getCount() {  
  21.         int count = 0;  
  22.         for (int i = 0; i < list.size(); i++) {  
  23.             Grade grade = (Grade) list.get(i);  
  24.             count += grade.getCount();  
  25.         }  
  26.         return count;  
  27.     }  
  28.   
  29.     public Composite remove(Grade grade) {  
  30.         list.remove(grade);  
  31.         return this;  
  32.     }  
  33.   
  34. }  

同时这里的add和romove方法返回this指针,这样袭用的dom4j的设计思想,操作的时候可以反复的中这个方法返回对象继续进行想要的操作,同时在这里的Composite类和Class*类实现的是统一接口,这样实现了功能的一致性,调用起来更显得方便,如下:

[java] view plaincopy
  1. composite.add(new ElectricalClass6()).add(new ElectricalClass7());  

最后通过客户端的调用体现了组合方法的实用性:

[java] view plaincopy
  1. package com.designpattern.composite;  
  2.   
  3. public class Client {  
  4.   
  5.     public static void main(String[] args) {  
  6.   
  7.         Composite grade = new Composite();  
  8.   
  9.         ElectricalClass6 class6 = new ElectricalClass6();  
  10.         ElectricalClass7 class7 = new ElectricalClass7();  
  11.         ElectricalClass8 class8 = new ElectricalClass8();  
  12.         ElectricalClass9 class9 = new ElectricalClass9();  
  13.   
  14.         grade.add(class6).add(class7);  
  15.         System.out.println("电气6班和电气7班的人数:" + grade.getCount());  
  16.   
  17.         grade.add(class8);  
  18.         System.out.println("电气6班和电气7班和电气8班的人数:" + grade.getCount());  
  19.   
  20.         grade.remove(class6);  
  21.         System.out.println("电气7班和电气8班的人数:" + grade.getCount());  
  22.   
  23.         System.out.println("电气7班的人数:" + grade.getChild(0).getCount());  
  24.         System.out.println("电气7班的人数:" + grade.remove(class8).getCount());  
  25.   
  26.     }  
  27. }  

输出结构测试:

[html] view plaincopy
  1. 电气6班和电气7班的人数:121  
  2. 电气6班和电气7班和电气8班的人数:191  
  3. 电气7班和电气8班的人数:138  
  4. 电气7班的人数:68  
  5. 电气7班的人数:68  

使用组合模式能够提供比使用集成关系更灵活的功能,并且可以灵活的组合子对象和父对象之间的关系,从而使客户端的调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不比关系自己处理的是单个对象还是整个组合结构,这样大大的减少了客户端的代码。

同时组合模式使得向集合添加新类型的组建变得容易,只要这些组建提供一个相似的变成接口即可,但这也是他的缺点,因为这种做法很难限制某个类。

没有更多推荐了,返回首页