组合模式可以构建部分-整体层次结构或构建数据的树形表示。总之,组合就是对象的集合,其中每个对象既可以是一个组合,也可以是简单的对象。对于树结构来说,有分支节点和叶子节点之说。
       总体上来说合成模式应该说是一种应用范围非常广的模式,最常见的莫过于树视图了,每个树视图的节点都可以添加子节点,不断重复就可以构成非常复杂的系统,常用的应用有菜单系统,文件系统都是基于树状结构的。Composite Pattern可分为安全和透明两种设计方式。

        透明模式:
       在Component抽象角色里面声明所有的用来管理子类对象的方法,包括add、remove,以及getSubordinates方法。这样做的好处是所有的构件类都有相同的接口。在客户端看来,树叶类对象与合成类对象的区别起码在接口层次上消失了,客户端可以同等同的对待所有的对象。这就是透明形式的合成模式。

这个选择的缺点是不够安全,因为树叶类对象和合成类对象在本质上是有区别的。树叶类对象不可能有下一个层次的对象,因此add、remove以及getSubordinates方法没有意义,是在编译时期不会出错,而只会在运行时期才会出错。所以在我们的例子中叶子节点的add,remove方法没有干任何的事情,只是简单的throw new Exception。

以上分为3个角色:

·       抽象构件(Component)角色:这是一个抽象类也可以为接口,它给参与组合的对象规定一个接口。这个角色给出共有接口及其默认行为。

·       树叶构件(Leaf)角色:代表参加组合的树叶对象。一个树叶对象没有下级子对象。

·       树枝构件(Composite)角色:代表参加组合的有子对象的对象,并给出树枝构件对象的行为。

由上图可知Composite对象可以包含其它Component对象。也就是说Composite类型对象可以含有其它的树枝(Composite)对象或树叶(Leaf)对象,这是一棵树的基本特征。
看看代码:

 1using System;
 2using System.Collections;
 3using Microsoft.Web.UI.WebControls;
 4namespace CompositeTree
 5{
 6    /// <summary>
 7    ///============== Program Description==============
 8    ///Name:CompositeTree.cs
 9    ///Objective:Composite 
10    ///Date:2006-05-12 
11    ///Written By coffee.liu
12    ///================================================
13    /// </summary>

14    
15    // "Component"
16    public abstract class Component
17    {
18        protected string name;
19        public Component( string name )
20        this.name = name; }
21        public string getName()
22        return name;
23        }

24        abstract public void Add(Component c);
25        abstract public void Remove( Component c );
26        abstract public IEnumerator getSubordinates();
27    }

28
29    // "Composite"
30    public class Composite : Component
31    {
32        private ArrayList children = new ArrayList();
33        public Composite( string name ) : base( name ) {}
34        public override void Add( Component component )
35        { children.Add( component ); }
36   
37        public override void Remove( Component component )
38        { children.Remove( component ); }
39        
40        public override IEnumerator getSubordinates()
41        {
42            return children.GetEnumerator ();
43        }

44    }

45 
46    // "Leaf"
47    public class Leaf : Component
48    {
49        private ArrayList childLeaf = new ArrayList(1);
50        // Constructors
51        public Leaf( string name ) : base( name ) {}
52 
53        // Methods
54        public override void Add( Component c )
55        throw new Exception("not added!"); }
56 
57        public override void Remove( Component c )
58        throw new Exception("not removed!"); }
59        public override IEnumerator getSubordinates()
60        {
61            return childLeaf.GetEnumerator();
62        }

63    }

64    
65    public class DisplayNode:TreeNode     
66    {
67        private Component cmpp;
68        public DisplayNode(Component cmp )
69        {
70            cmp.getName ();
71            cmpp = cmp;    
72            this.Text=cmp.getName ();
73        }

74
75    }

76
77}

78

再看看页面代码

  1using System;
  2using System.Collections;
  3using System.ComponentModel;
  4using System.Data;
  5using System.Drawing;
  6using System.Web;
  7using System.Web.SessionState;
  8using System.Web.UI;
  9using System.Web.UI.WebControls;
 10using System.Web.UI.HtmlControls;
 11
 12namespace CompositeTree
 13{
 14    /// <summary>
 15    ///============== Program Description==============
 16    ///Name:WebForm1.aspx.cs
 17    ///Objective:Composite 
 18    ///Date:2006-05-12 
 19    ///Written By coffee.liu
 20    ///================================================
 21    /// </summary>

 22    public class WebForm1 : System.Web.UI.Page
 23    {
 24        protected Microsoft.Web.UI.WebControls.TreeView TreeView1;
 25        Component prez,pxi1,pxi2,pjy1,pjy2,pjy3,pjy4,pjs1,pjs2,pjs3,pjs4,pjs5,pjs6,pjs7;
 26        private void buildDisplayList() 
 27        {
 28            prez = new Composite("南京铁道职业技术学院");
 29            pxi1=new Composite("通信工程系");
 30            pxi2=new Composite("计算机系");
 31            prez.Add(pxi1);
 32            prez.Add(pxi2);
 33            pjy1=new Composite("网络教研室");
 34            pjy2=new Composite("通讯教研室");
 35            pjy3=new Composite("移动通信教研室");
 36            pxi1.Add(pjy1);
 37            pxi1.Add(pjy2);
 38            pxi1.Add(pjy3);
 39            pjy4=new Composite("软件");
 40            pxi2.Add(pjy4);
 41            pjs1=new Leaf("沈瑞琴");
 42            pjy1.Add(pjs1);
 43            pjs2=new Leaf("晏荣");
 44            pjy1.Add(pjs2);
 45            pjs3=new Leaf("蒋明华");
 46            pjy1.Add(pjs3);
 47            pjs4=new Leaf("赵丽花");
 48            pjy1.Add(pjs4);
 49            pjs5=new Leaf("康瑞峰");
 50            pjy1.Add(pjs5);
 51            pjs6=new Leaf("冯明兵");
 52            pjy1.Add(pjs6);
 53            pjs7=new Leaf("刘伟");
 54            pjy1.Add(pjs7);
 55                    
 56        }

 57        private void buildTree() 
 58        {
 59            DisplayNode nod;
 60
 61            nod = new DisplayNode(prez);
 62            TreeView1.Nodes.Add(nod);
 63            addNodes(nod, prez);
 64        }

 65        private void addNodes(DisplayNode nod, Component cmp) 
 66        {
 67            Component newCmp;
 68            DisplayNode newNode;
 69            IEnumerator cmpEnum;
 70            cmpEnum = cmp.getSubordinates();
 71
 72            while (cmpEnum.MoveNext()) 
 73            {
 74                newCmp = (Component)cmpEnum.Current;
 75                newNode = new DisplayNode(newCmp);
 76                nod.Nodes.Add(newNode);
 77                addNodes(newNode, newCmp);
 78            }

 79        }

 80        private void Page_Load(object sender, System.EventArgs e)
 81        {
 82            
 83            buildDisplayList();
 84            buildTree();
 85
 86        }

 87
 88        Web 窗体设计器生成的代码
109
110        
111    }

112}

113

生成的页面如图:


再看看Pasal的树结构代码:

  1unit UnitCompositeTree;
  2//============== Program Description==============
  3    //Name:CompositeTree.dpr
  4    //Objective:CompositeTree
  5    //Date:2006-05-15
  6    //Written By coffee.liu
  7    //================================================
  8interface
  9
 10uses
 11  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 12  Dialogs, StdCtrls, ComCtrls;
 13    // "Component"
 14  type
 15  Component= class(TComponent)
 16      protected  name:string;
 17      public
 18        function  getName():string;
 19        procedure Add(c:Component);virtual;abstract;
 20        procedure Remove( c:Component  );virtual;abstract;
 21        function getSubordinates():TList;virtual;abstract;
 22        constructor create(aname:string);
 23        destructor Destroy();override;
 24  end;
 25  // "Composite"
 26   type
 27   Composite= class(Component)
 28
 29       private  children:TList;
 30       public
 31       constructor create(aname:string);
 32       procedure Add(acomponent:Component);override;
 33       procedure Remove(acomponent:Component);override;
 34       function getSubordinates():TList;override;
 35       destructor Destroy();override;
 36   end;
 37   type
 38   Leaf=class(Component)
 39       private  childLeaf:TList;
 40       public
 41       constructor create(aname:string);
 42       procedure Add(acomponent:Component);override;
 43       procedure Remove(acomponent:Component);override;
 44       function getSubordinates():TList;override;
 45       destructor Destroy();override;
 46    end;
 47    type
 48    DisplayNode= class(TTreeNode)
 49       private cmpp:Component;
 50       public
 51        constructor create(tr:TTreeNodes;cmp:Component);
 52         procedure setcomp(cmp:Component);
 53         destructor Destroy();override;
 54  
 55  end;
 56
 57   type EErrorMethod=class(Exception);//定制异常
 58type
 59  TForm1 = class(TForm)
 60    TreeView1: TTreeView;
 61    procedure FormCreate(Sender: TObject);
 62    procedure FormClose(Sender: TObject; var Action: TCloseAction);
 63  private
 64    { Private declarations }
 65  public
 66     procedure buildDisplayList(); 
 67      procedure buildTree();
 68      procedure addNodesL(anod:TTreeNode;acmp:Component);
 69  end;
 70   PTreeViewItem = ^DisplayNode;
 71var
 72  Form1: TForm1;
 73  prez,pxi1,pxi2,pjy1,pjy2,pjy3,pjy4,pjs1,pjs2,pjs3,pjs4,pjs5,pjs6,pjs7:Component;
 74  nod:DisplayNode;
 75  MyTreeNode,MyTreeNode1: TTreeNode;
 76implementation
 77
 78{$R *.dfm}
 79
 80{ Component }
 81
 82constructor Component.create(aname: string);
 83begin
 84   name:=aname;
 85   Form1.InsertComponent(self);
 86end;
 87
 88destructor Component.Destroy;
 89begin
 90
 91  inherited;
 92end;
 93
 94function Component.getName: string;
 95begin
 96  result:=name;
 97end;
 98
 99{ Composite }
100
101procedure Composite.Add(acomponent: Component);
102begin
103   children.Add(acomponent);
104
105end;
106
107constructor Composite.create(aname: string);
108begin
109   inherited;
110    children:=TList.Create;
111end;
112
113destructor Composite.Destroy;
114begin
115  if Assigned(children) then children.Free;
116  inherited;
117end;
118
119function Composite.getSubordinates: TList;
120begin
121    result:=children;
122end;
123
124
125
126procedure Composite.Remove(acomponent: Component);
127begin
128     children.Remove(acomponent);
129end;
130
131{ Leaf }
132
133procedure Leaf.Add(acomponent: Component);
134begin
135raise EErrorMethod.Create('Leaf not been added!');
136end;
137
138constructor Leaf.create(aname: string);
139begin
140  inherited;
141    childLeaf:=TList.Create;
142end;
143
144destructor Leaf.Destroy;
145begin
146 if Assigned(childLeaf) then childLeaf.Free;
147  inherited;
148end;
149
150function Leaf.getSubordinates: TList;
151begin
152   result:=childLeaf;
153end;
154
155
156
157procedure Leaf.Remove(acomponent: Component);
158begin
159 raise EErrorMethod.Create('Leaf not been removed!');
160end;
161
162{ DisplayNode }
163
164constructor DisplayNode.create(tr:TTreeNodes;cmp: Component);
165begin
166 inherited create(tr);
167    cmpp:=cmp;
168     self.Text:=cmpp.getName;
169end;
170
171destructor DisplayNode.Destroy;
172begin
173 if Assigned(cmpp)then cmpp.Free;
174  inherited;
175end;
176
177procedure DisplayNode.setcomp(cmp: Component);
178begin
179    cmpp:=cmp;
180    self.Text:=cmpp.getName;
181end;
182
183{ TForm1 }
184
185procedure TForm1.buildDisplayList;
186begin
187           prez := Composite.create('南京铁道职业技术学院');
188           pxi1:=Composite.create('通信工程系');
189           pxi2:=Composite.create('计算机系');
190           prez.Add(pxi1);
191           prez.Add(pxi2);
192           pjy1:=Composite.create('网络教研室');
193           pjy2:=Composite.create('通讯教研室');
194           pjy3:=Composite.create('移动通信教研室');
195           pxi1.Add(pjy1);
196           pxi1.Add(pjy2);
197           pxi1.Add(pjy3);
198           pjy4:=Composite.create('软件');
199           pxi2.Add(pjy4);
200           pjs1:=Leaf.create('沈瑞琴');
201           pjy1.Add(pjs1);
202           pjs2:=Leaf.create('晏荣');
203           pjy1.Add(pjs2);
204           pjs3:=Leaf.create('蒋明华');
205           pjy1.Add(pjs3);
206           pjs4:=Leaf.create('赵丽花');
207           pjy1.Add(pjs4);
208           pjs5:=Leaf.create('康瑞峰');
209           pjy1.Add(pjs5);
210           pjs6:=Leaf.create('冯明兵');
211           pjy1.Add(pjs6);
212           pjs7:=Leaf.create('刘伟');
213           pjy1.Add(pjs7);
214
215end;
216
217procedure TForm1.buildTree;
218begin
219            TreeView1.Items.Clear;
220           MyTreeNode:=TreeView1.Items.Add(nil,prez.getName);
221            addNodesL(MyTreeNode, prez);
222end;
223
224procedure TForm1.addNodesL(anod: TTreeNode; acmp: Component);
225var
226i:integer;
227 newCmp:Component ;
228 cmpEnum:TList;
229begin
230 cmpEnum := acmp.getSubordinates();
231 for i:=0 to cmpEnum.Count-1 do
232        begin
233           newCmp := Component(cmpEnum[i]);
234           MyTreeNode:=TreeView1.Items.AddChild(anod,newCmp.getName);
235            addNodesL(MyTreeNode, newCmp);
236         end;
237end;
238
239procedure TForm1.FormCreate(Sender: TObject);
240begin
241     buildDisplayList;
242           buildTree;
243end;
244procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
245begin
246Application.Terminate;
247end;
248
249end.
250

运行效果:
Image00019.gif

     2.安全模式

          第二种选择是在Composite类里面声明所有的用来管理子类对象的方法。这样的做法是安全的做法,因为树叶类型的对象根本就没有管理子类对象的方法,因此,如果客户端对树叶类对象使用这些方法时,程序会在编译时期出错。这个选择的缺点是不够透明,因为树叶类和合成类将具有不同的接口。

   
由图可以看出Leaf(leafSafe)去掉了容易引起错误的Add,Remove方法。
 

·       抽象构件(Component)角色:这是一个抽象角色,其定义出统一接口行为但它并不定义出管理子对象的方法如Add、Remove方法,这一定义由树枝构件对象给出。

·       树叶构件(Leaf)角色:树叶对象没有子对象,它只是定义出参加组合的原始对象的行为。

·       树枝构件(Composite)角色:代表参加组合的有下级子对象的对象。树枝对象给出所有的管理子对象的方法,如add、remove等。

在上面例子的基础上代码修改也十分的容易:

 1using System;
 2using System.Collections;
 3using Microsoft.Web.UI.WebControls;
 4
 5namespace CompositeTree
 6{
 7    /// <summary>
 8    ///============== Program Description==============
 9    ///Name:CompositeTree1.cs
10    ///Objective:ComponentSafe 
11    ///Date:2006-05-14
12    ///Written By coffee.liu
13    ///================================================
14    /// </summary>
15    /// // "Component"

16    public abstract class ComponentSafe
17    {
18        protected string name;
19        public ComponentSafe( string name )
20        this.name = name; }
21        public string getName()
22        {
23                return name;
24        }

25      abstract public IEnumerator getSubordinates();
26        
27    }

28
29    // "Composite"
30    public class CompositeSafe : ComponentSafe
31    {
32        private ArrayList children = new ArrayList();
33        public CompositeSafe( string name ) : base( name ) {}
34        public  void Add( ComponentSafe component )
35        { children.Add( component ); }
36   
37        public  void Remove( ComponentSafe component )
38        { children.Remove( component ); }
39        
40        public override IEnumerator getSubordinates()
41        {
42            return children.GetEnumerator ();
43        }

44    }

45 
46    // "Leaf"
47    public class LeafSafe : ComponentSafe
48    {
49        private ArrayList childLeaf = new ArrayList(1);
50        // Constructors
51        public LeafSafe( string name ) : base( name ) {}
52        public override IEnumerator getSubordinates()
53        {
54            return childLeaf.GetEnumerator();
55        }

56    }

57    
58    public class DisplayNodeSafe:TreeNode     
59    {
60        private ComponentSafe cmpp;
61        public DisplayNodeSafe(ComponentSafe cmp )
62        {
63            cmp.getName ();
64            cmpp = cmp;    
65            this.Text=cmp.getName ();
66        }

67
68    }

69
70    
71}

72

页面代码也只需要修改

 1 //Component prez,pxi1,pxi2,pjy1,pjy2,pjy3,pjy4,pjs1,pjs2,pjs3,pjs4,pjs5,pjs6,pjs7;
 2         CompositeSafe root;
 3        private void buildDisplayList() 
 4        {
 5            root = new CompositeSafe("南京铁道职业技术学院");
 6            CompositeSafe rootxi=new CompositeSafe("通信工程系");
 7            root.Add(rootxi);
 8            CompositeSafe rootxi1=new CompositeSafe("计算机系");
 9            root.Add(rootxi1);
10            CompositeSafe rootjywl=new CompositeSafe("网络教研室");
11            CompositeSafe rootjytx=new CompositeSafe("通讯教研室");
12            CompositeSafe rootjyyd=new CompositeSafe("移动通信教研室");
13            rootxi.Add(rootjywl);
14            rootxi.Add(rootjytx);
15            rootxi.Add(rootjyyd);
16            
17            CompositeSafe rootjyrj=new CompositeSafe("软件");
18            rootxi1.Add(rootjyrj);
19            
20            rootjywl.Add(new LeafSafe("沈瑞琴"));
21            rootjywl.Add(new LeafSafe("晏荣"));
22            rootjywl.Add(new LeafSafe("蒋明华"));
23            rootjywl.Add(new LeafSafe("赵丽花"));
24            rootjywl.Add(new LeafSafe("康瑞峰"));
25            rootjywl.Add(new LeafSafe("冯明兵"));
26            rootjywl.Add(new LeafSafe("刘伟"));
27            
28                    
29        }

即可。同理上面的Pascal代码按照这一思路修改也可。


 




 

posted on 2006-05-08 23:46  coffeeliu  阅读(570)  评论(3编辑  收藏  举报