经常使用Control,会发现Control有Controls的属性,而Controls集合包含的还是一个Control,类似的还有XmlNode.他们都有一个共有的特性,数据结构都是树行结构,什么是树形模式呢?
树(Tree)是n(n≥0)个结点的有限集T,T为空时称为空树,否则它满足如下两个条件:
(1) 有且仅有一个特定的称为根(Root)的结点;
(2) 其余的结点可分为m(m≥0)个互不相交的子集Tl,T2,…,Tm,其中每个子集本身又是一棵树,并称其为根的子树(SubTree)。上面给出的递归定义刻画了树的固有特性:一棵非空树是由若干棵子树构成的,而子树又可由若干棵更小的子树构成。而这里的子树可以是叶子也可以是分支。
先看下一幅图,里面的套娃就是一个套着一个的
这样一堆娃娃,一个大的套一个小的,小的里面还可以套更小的,所以其组织结构为:
Top Toy
- Toy
-- toy
----toy
----toy
如果用程序来描述上图,用设计模式的组合模式(Composite)是一个不错的主意
组合模式在GOF中定义为: 组合(Composite)模式将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。
类图为:
可以说,组合模式是比较简单易学的设计模式,我按照其定义和规则,实现一个论坛主题,帖子的组合关系
论坛中,一个主题可以包括很多帖子 ,一个帖子还可以包括很多回复。关系是:
Thread
-- Thread||Message
-- Thread||Message
下面是实现文件:
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5namespace CompositeStudy
6{
7 public interface IThread
8 {
9 void Add(IThread thread);
10 void Remove(IThread thread);
11 void RenderContent();
12 }
13}
14
15using System;
16using System.Collections.Generic;
17using System.Text;
18
19namespace CompositeStudy
20{
21 public abstract class AbstractThread : IThread
22 {
23 bool _isTop;
24 public bool IsTop
25 {
26 get
27 {
28 return _isTop;
29 }
30 set
31 {
32 _isTop = value;
33 }
34 }
35 List<IThread> list = new List<IThread>();
36 public List<IThread> Children
37 {
38 get
39 {
40 return list;
41 }
42 set
43 {
44 list = value;
45 }
46 }
47 string content = "";
48 public string Content
49 {
50 get
51 {
52 return content;
53 }
54 set
55 {
56 content = value;
57 }
58 }
59 public void Add(IThread thread)
60 {
61 list.Add(thread);
62 }
63 public void Remove(IThread thread)
64 {
65 list.Remove(thread);
66 }
67 public abstract void RenderContent();
68 }
69}
70
71
72using System;
73using System.Collections.Generic;
74using System.Text;
75
76namespace CompositeStudy
77{
78 public class Thread : AbstractThread
79 {
80
81 public override void RenderContent()
82 {
83 //输出自己的Contetn
84 Console.WriteLine("Thread:"+this.Content);
85 foreach (IThread t in Children)
86 {
87 t.RenderContent();
88 }
89 }
90 }
91}
92
93
94using System;
95using System.Collections.Generic;
96using System.Text;
97
98namespace CompositeStudy
99{
100 public class Message:AbstractThread
101 {
102 public override void RenderContent()
103 {
104 Console.WriteLine("Message:" + this.Content);
105 foreach (IThread t in Children)
106 {
107 t.RenderContent();
108 }
109 }
110
111 }
112}
113
114
工厂类为:
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Data;
5
6 namespace CompositeStudy
7 {
8 /**//// <summary>
9 /// 工厂类
10 /// </summary>
11 /// <remarks>工厂类</remarks>
12 public class ThreadFactory
13 {
14 DataTable table = new DataTable();
15 public ThreadFactory()
16 {
17 table.Columns.Add("content");
18 table.Columns.Add("IsTop");
19 table.Columns.Add("IsMessage");
20 table.Columns.Add("ID");
21 table.Columns.Add("ParentID");
22
23 DataRow row = table.NewRow();
24 row["content"] = "test";
25 row["IsTop"] = false;
26 row["IsMessage"] = false;
27 row["ID"] = 1;
28 row["ParentID"] = 0;
29 table.Rows.Add(row);
30
31 row = table.NewRow();
32 row["content"] = "test1";
33 row["IsTop"] = true;
34 row["IsMessage"] = false;
35 row["ID"] = 0;
36 row["ParentID"] = -1;
37 table.Rows.Add(row);
38
39 row = table.NewRow();
40 row["content"] = "test2";
41 row["IsTop"] = false;
42 row["IsMessage"] = true;
43 row["ID"] = 2;
44 row["ParentID"] = 0;
45 table.Rows.Add(row);
46
47 row = table.NewRow();
48 row["content"] = "test3";
49 row["IsTop"] = false;
50 row["IsMessage"] = true;
51 row["ID"] = 3;
52 row["ParentID"] = 0;
53 table.Rows.Add(row);
54 }
55 public List<IThread> GetTopThreads()
56 {
57 List<IThread> list = new List<IThread>();
58 DataRow[] rows = table.Select("IsTop = true");
59 foreach (DataRow row in rows)
60 {
61 Thread t = new Thread();
62 t.Content = row["content"].ToString();
63 t.IsTop = true;
64 DataRow[] cs = table.Select("ParentID="+Convert.ToInt32(row["ID"]));
65 foreach (DataRow r in cs)
66 {
67 if (Convert.ToBoolean(r["IsMessage"]))
68 {
69 Message m = new Message();
70 m.Content = r["content"].ToString();
71 m.IsTop = false;
72 t.Add(m);
73 }
74 else
75 {
76 Thread tt = new Thread();
77 tt.Content = r["content"].ToString();
78 tt.IsTop = false;
79 t.Add(tt);
80 }
81 }
82 list.Add(t);
83 }
84 return list;
85 }
86 }
87}
88
客户端调用方法为:
2 using System.Collections.Generic;
3 using System.Text;
4
5 namespace CompositeStudy
6 {
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 ThreadFactory factory = new ThreadFactory();
12 List<IThread> threads = factory.GetTopThreads();
13 foreach(IThread t in threads)
14 {
15 t.RenderContent();
16 }
17 Console.Read();
18 }
19 }
20}
21
类关系图:
输结果为:
通过该事例的调用,就可以知道,组合模式的好处有:
1) 使客户端调用简单,客户端可以一致的使用组合结构或其中单个对象,用户就不必关心自己处理的是单个对象还是整个组合结构,这就简化了客户端代码。
2) 更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。这一点符合开闭原则的要求,对系统的二次开发和功能扩展很有利!