重新看组合/合成(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 }
View Code

适用Composite模式的情况:

1、想要表示对象的部分-整体层次结构

2、希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

第一句话很好理解,第二句话该怎么理解呢?我的理解是,如果有一个方法Visist(Component con){con.Draw();}实现一个动作,这时候它并不需要知道是处理一个叶子结点对象还是一个组合对象,对于传进来的叶子结点对象,可以直接处理请求,如果是一个Composite,则将请求发给它的子部件,并且在转发请求之前/后还可以执行一些辅助操作。有人举过一个例子:文件和文件夹,该实现可以用组合模式,文件是Leaf,文件夹是Composite,我们可以单建文件对象,也可创建一个具有目录结构的文件夹对象,文件夹下面可以放文件对象,也可以放文件夹对象。

为了提高系统的可复用性,有一些设计原则,其中有一条“组合/聚合复用原则”,就是优先使用“组合/聚合”,而非继承,这里说的组合是对象组合,也就是一个对象在运行时期动态获得其他对象的引用,从而达到不用继承而能扩展功能的效果;显然,对象组合的使用范围更大,和这里的组合模式不是同一个概念,前者毕竟是一个“设计原则”,而后者则是一个成型的“模式”,原则的使用范围当然更广了。

通过今天的总结,对组合模式又有了进一步的认识,感谢GOF、《Java与模式》、《Thinking in Patterns》。

 

posted on 2017-08-13 21:15  Judy518  阅读(126)  评论(0编辑  收藏  举报