重新看组合/合成(Composite)模式,发现它并不像自己想象的那么简单,单纯从整体和部分关系的角度去理解还是不够的,并且还有一些通俗的模式讲解类的书,由于其举的例子太过“通俗”,以致让人理解产生偏差,不过设计模式本身就是一种程序设计思想,不同的人当然会产生具有偏差性质的理解。
GOF对组合模式的定义是:将对象组合成树形结构以表示“部分 -整体”的层次结构。 Composite使得用户对单个对象和组合对象的使用具有一致性 。这里,“用户对单个对象和组合对象的使用具有一致性”,这是Composite模式产生的效果。从表示形式来看,Composite表示的是“部分-整体”的关系,但是,往往忽略了效果。下图是Composite模式的结构图:
Composite模式的对象结果如下:
Composite类提供对Leaf类对象的管理方法,如Add(),Remove(),GetChild()方法,这些方法的定义可以有两种方法:一个是放在Component的顶层父类中,这样所有的子类(包括Leaf类)都会集成该方法,但Leaf类可以选择不实现这些方法;另外一个是将对Leaf对象操作的方法放到Composite类中,并不是放到Component类中。现在以GOF所著书中所给的例子为例,写出组合模式的代码,类图结构如下:
代码如下:
1 abstract class Graphic{ 2 3 public void Draw(){} 4 public void Add(Graphic g){} 5 public void Remove(Graphic g){} 6 public Graphic GetChild(int index){return null;} 7 } 8 class Line extends Graphic{ 9 public void Draw(){ 10 System.out.println("Draw a Line"); 11 } 12 } 13 class Rectange extends Graphic{ 14 public void Draw(){ 15 System.out.println("Draw a Rectange"); 16 } 17 } 18 class Text extends Graphic{ 19 public void Draw(){ 20 System.out.println("Draw a Text"); 21 } 22 } 23 class Picture extends Graphic{ 24 private Vector<Graphic> vec=new Vector<Graphic>(); 25 public void Draw(){ 26 for(Graphic g : vec){ 27 g.Draw(); 28 } 29 } 30 public void Add(Graphic g){ 31 vec.add(g); 32 } 33 public void Remove(Graphic g){ 34 try{ 35 vec.remove(g); 36 }catch(Exception e){ 37 38 } 39 } 40 public Graphic GetChild(int index){ 41 return vec.get(index); 42 } 43 } 44 public class Test{ 45 public static void main(String[] args){ 46 Picture p=new Picture(); 47 p.Add(new Text()); 48 p.Add(new Rectange()); 49 p.Add(new Line()); 50 p.Draw(); 51 } 52 }
适用Composite模式的情况:
1、想要表示对象的部分-整体层次结构
2、希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
第一句话很好理解,第二句话该怎么理解呢?我的理解是,如果有一个方法Visist(Component con){con.Draw();}实现一个动作,这时候它并不需要知道是处理一个叶子结点对象还是一个组合对象,对于传进来的叶子结点对象,可以直接处理请求,如果是一个Composite,则将请求发给它的子部件,并且在转发请求之前/后还可以执行一些辅助操作。有人举过一个例子:文件和文件夹,该实现可以用组合模式,文件是Leaf,文件夹是Composite,我们可以单建文件对象,也可创建一个具有目录结构的文件夹对象,文件夹下面可以放文件对象,也可以放文件夹对象。
为了提高系统的可复用性,有一些设计原则,其中有一条“组合/聚合复用原则”,就是优先使用“组合/聚合”,而非继承,这里说的组合是对象组合,也就是一个对象在运行时期动态获得其他对象的引用,从而达到不用继承而能扩展功能的效果;显然,对象组合的使用范围更大,和这里的组合模式不是同一个概念,前者毕竟是一个“设计原则”,而后者则是一个成型的“模式”,原则的使用范围当然更广了。
通过今天的总结,对组合模式又有了进一步的认识,感谢GOF、《Java与模式》、《Thinking in Patterns》。