大B:“经常使用Control,你会发现Control有Controls的属性,而Controls集合包含的还是一个Control,类似的还有XmlNode。他们都有一个共有的特性,数据结构都是树行结构。”
小A:“什么是树形模式呢?”
大B:“树(Tree)是n(n≥0)个结点的有限集T,T为空时称为空树,否则它满足如下两个条件:1、有且仅有一个特定的称为根(Root)的结点;2、 其余的结点可分为m(m≥0)个互不相交的子集Tl,T2,…,Tm,其中每个子集本身又是一棵树,并称其为根的子树(SubTree)。”
大B:“上面给出的递归定义刻画了树的固有特性:一棵非空树是由若干棵子树构成的,而子树又可由若干棵更小的子树构成。而这里的子树可以是叶子也可以是分支。先看下一幅图,如图5-2所示,里面的套娃就是一个套着一个的。”
图5-2 套娃
这样一堆娃娃,一个大的套一个小的,小的里面还可以套更小的,所以其组织结构为:
Top toy
-Toy
--toy
---toy
----toy
abstract class CompositeEquipment extends Equipment { private int i=0; //定义一个Vector 用来存放'儿子' private Lsit equipment=new ArrayList(); public CompositeEquipment(String name) { super(name); } public boolean add(Equipment equipment) { this.equipment.add(equipment); return true; } public double netPrice() { double netPrice=0.; Iterator iter=equipment.iterator(); for(iter.hasNext()) netPrice+=((Equipment)iter.next()).netPrice(); return netPrice; } public double discountPrice() { double discountPrice=0.; Iterator iter=equipment.iterator(); for(iter.hasNext()) discountPrice+=((Equipment)iter.next()).discountPrice(); return discountPrice; } //注重这里,这里就提供用于访问自己组合体内的部件方法。 //上面dIsk 之所以没有,是因为Disk是个单独(Primitive)的元素. public Iterator iter() { return equipment.iterator() { //重载Iterator方法 public boolean hasNext() { return i
abstract class CompositeEquipment extends Equipment { private int i=0; //定义一个Vector 用来存放'儿子' private Lsit equipment=new ArrayList(); public CompositeEquipment(String name) { super(name); } public boolean add(Equipment equipment) { this.equipment.add(equipment); return true; } public double netPrice() { double netPrice=0.; Iterator iter=equipment.iterator(); for(iter.hasNext()) netPrice+=((Equipment)iter.next()).netPrice(); return netPrice; } public double discountPrice() { double discountPrice=0.; Iterator iter=equipment.iterator(); for(iter.hasNext()) discountPrice+=((Equipment)iter.next()).discountPrice(); return discountPrice; } //注重这里,这里就提供用于访问自己组合体内的部件方法。 //上面dIsk 之所以没有,是因为Disk是个单独(Primitive)的元素. public Iterator iter() { return equipment.iterator() { //重载Iterator方法 public boolean hasNext() { return i
大B:“如果用程序来描述图5-2套娃,用设计模式的组合模式(Composite)是一个不错的主意。组合模式在GOF中定义为:组合(Composite)模式将对象以树形结构组织起来,以达成‘部分-整体’的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。”
类图如图5-3所示:
图5-3 类图
大B:“可以说,组合模式是比较简单易学的设计模式,我按照其定义和规则,实现一个论坛主题,帖子的组合关系。论坛中,一个主题可以包括很多帖子 ,一个帖子还可以包括很多回复。”
关系是:
Thread
-- Thread||Message
---- Thread||Message
下面是实现文件:
using System; using System.Collections.Generic; using System.Text; namespace CompositeStudy { public interface IThread { void Add(IThread thread); void Remove(IThread thread); void RenderContent(); } }
using System; using System.Collections.Generic; using System.Text; namespace CompositeStudy { public abstract class AbstractThread : IThread { bool _isTop; public bool IsTop { get { return _isTop; } set { _isTop = value; } } List list = new List(); public List Children { get { return list; } set { list = value; } } string content = ""; public string Content { get { return content; } set { content = value; } } public void Add(IThread thread) { list.Add(thread); } public void Remove(IThread thread) { list.Remove(thread); } public abstract void RenderContent(); } }
using System; using System.Collections.Generic; using System.Text; namespace CompositeStudy { public class Thread : AbstractThread { public override void RenderContent() { //输出自己的Contetn Console.WriteLine("Thread:"+this.Content); foreach (IThread t in Children) { t.RenderContent(); } } } }
using System; using System.Collections.Generic; using System.Text; namespace CompositeStudy { public class Message:AbstractThread { public override void RenderContent() { Console.WriteLine("Message:" + this.Content); foreach (IThread t in Children) { t.RenderContent(); } } } }
工厂类为:
using System; using System.Collections.Generic; using System.Text; using System.Data; namespace CompositeStudy { /**/////// 工厂类 /// /// 工厂类 public class ThreadFactory { DataTable table = new DataTable(); public ThreadFactory() { table.Columns.Add("content"); table.Columns.Add("IsTop"); table.Columns.Add("IsMessage"); table.Columns.Add("ID"); table.Columns.Add("ParentID"); DataRow row = table.NewRow(); row["content"] = "test"; row["IsTop"] = false; row["IsMessage"] = false; row["ID"] = 1; row["ParentID"] = 0; table.Rows.Add(row); row = table.NewRow(); row["content"] = "test1"; row["IsTop"] = true; row["IsMessage"] = false; row["ID"] = 0; row["ParentID"] = -1; table.Rows.Add(row); row = table.NewRow(); row["content"] = "test2"; row["IsTop"] = false; row["IsMessage"] = true; row["ID"] = 2; row["ParentID"] = 0; table.Rows.Add(row); row = table.NewRow(); row["content"] = "test3"; row["IsTop"] = false; row["IsMessage"] = true; row["ID"] = 3; row["ParentID"] = 0; table.Rows.Add(row); } public List GetTopThreads() { List list = new List(); DataRow[] rows = table.Select("IsTop = true"); foreach (DataRow row in rows) { Thread t = new Thread(); t.Content = row["content"].ToString(); t.IsTop = true; DataRow[] cs = table.Select("ParentID="+Convert.ToInt32(row["ID"])); foreach (DataRow r in cs) { if (Convert.ToBoolean(r["IsMessage"])) { Message m = new Message(); m.Content = r["content"].ToString(); m.IsTop = false; t.Add(m); } else { Thread tt = new Thread(); tt.Content = r["content"].ToString(); tt.IsTop = false; t.Add(tt); } } list.Add(t); } return list; } } }
客户端调用方法为:
using System; using System.Collections.Generic; using System.Text; namespace CompositeStudy { class Program { static void Main(string[] args) { ThreadFactory factory = new ThreadFactory(); List threads = factory.GetTopThreads(); foreach(IThread t in threads) { t.RenderContent(); } Console.Read(); } } }
类关系图如图5-4所示:
图5-4 类关系图
输结果为: