/// <summary>
/// PS: 在写这个文章时想用的标题是 Composite 模式和其他模式,后来感觉想写的不只是其他模式的关系
/// 就写了这个标题,好象语法不通,但没办法,从中学开始语文考试就没超过60分^-^
/// </summary>
当使用抽象类的时候我们可以先定义一个 Component 抽象类 , 在类里加了两个重载的方法 IsTree
用于判断合成对象是否的树结构.
public abstract class Component
{
private string _strName = string.Empty;
private Component _parent; // 父对象
public Component(string name)
{
this._strName = name;
}
public string Name{get {return this._strName;}}
public Component Parent{get{return this._parent;}}
public bool IsTree()
{
return this.IsTree(new Hashtable());
}
public abstract bool IsTree(Hashtable visited);
}
在 Composite 类和 Leaf 类里实现 IsTree 方法都很简单,只要检查 Coomposite 对象的 Name 是否在访问的哈希表中出现过,并且要检查 COmposite 对象的子对象是否是树结构
public class Composite : Component
{
private IList _listChild;
public Composite(string name):base(name){}
public IList ChildComponentItems
{
get{return this._listChild;}
}
public override bool IsTree(Hashtable visited)
{
visited.Add(this.Name, this);
foreach (Component dc in this.ChildComponentItems)
{
if (visited.Contains(dc.Name) || !dc.IsTree(visited))
{
return false;
}
}
return true;
}
}
在 Leaf 类里就更简单了,因为 Leaf 对象本身肯定是树结构,只要在访问的哈希表中记录 Leaf 对象的 Name 就可以了
public class Leaf : Component
{
public Leaf(string name):base(name){}
public override bool IsTree(Hashtable visited)
{
visited.Add(this.Name, this);
return true;
}
}
现在.我们的合成模式可以判断是否是树结构了.
现在我们终于能开始考虑第二个思想了(是思想不是法律!!!,不实现不违法!)
他让我们把合成对象和叶对象的操作提供一个统一的接口或抽象,苍天哪!
在 Composite 模式中有几个常用的操作
public bool Contains(string name);
public Component Find(string name);
public int GetDeviceCount();
实现了这些操作或方法后,我们就要对合成对象和叶对象进行抽象了,具体怎么抽象,抽象什么和我们的合成对象的应用有关.
第一次应用 Composite 模式是在做工业控制项目中用于设备管理.在设备管理中要求实现设备树.其中节点就是合成对象,他可以添加设备或其他的节点,设备就是叶(在实际中,还有总线设备,他也可以添加设备,为了讨论方便,这里就把他排除在外).
OK,现在就对这些节点和设备抽象了.
首先看抽象什么,在对设备来说有一些常规操作比如 连接断开设备,打开关闭设备和读写设备等.这些我们可以把他抽象到顶层抽象类 Component 中.在 Leaf 类里实现这些抽象方法是直接操作设备,在节点里是通过迭代操作节点里的所有设备
这样我可以对节点和设备使用同一个抽象来操作,比如我们可以选择打开一个设备,也可以打开一个节点下的所有设备.两种操作对使用合成对象的客户代码是一样的.
可有些对设备的操作比较特殊,不适合在节点里对成批的设备同时操作(这种情况在其他的合成对象也会遇到),这些方法需要抽象到 Component 类里吗? 郁闷第二次.如果把这些操作都抽象到 Component 类里,Component 类会不会很变态?
同时,现实中设备千差万别,我们怎么对这些设备进行抽象.或者说,我们要把 Leaf 作为其他设备类的顶层抽象.那 Leaf 要有那些功能.怎么把各种设备的操作抽象到 Leaf 中,还有怎么根据设备的主要特性设定设备子类的继承关系,比如我们可以根据设备的连接形式来确定设备子类的继承关系
比如对于板卡类的设备,我可以定义一个类继承 Leaf 类
public class CardDevice : Leaf
{
......
}
在这个类里,我们会实现板卡通讯的基本功能
同时对于 RS323(串口)连接的设备,我们可以定义一个类,同样继承 Leaf 类
public class RS232Device : Leaf
{
.......
}
在 RS232Device 类里我们实现了和 RS232 口通讯的基本功能,
这样我们在扩充设备时,如果设备是用板卡的就可以继承 CardDevice 类,同样如果设备使用 RS232 口就可以继承 RS232Device 类. 很好的解决方案,不是吗?
确实不是!
假如我们板卡和串口的通讯方式都有了新的版本,为了实现新的版本我们重新定义两个类来扩充新的协议,
public class CardDevice2 : CardDevice
{
......
}
public class RS232Device2 : RS232Device
{
.......
}
假如板卡的扩充和串口的扩充都增加了一个相同的控制方式,比如都可以用很通用命令让设备说 "Hello World",很夸张.哈哈.那这个方式在以前的版本实现不了,那么我们就要在 CardDevice2 和 RS232Device 类都要实现,并且两个类里的代码几乎是一致的,那么代码重用在这里只能表现为粘贴和复制了.
幸好还个 桥接(Bridge)模式,他的广告词是: 将抽象部分与实现部分分离,使它们都可以独立的变化.
好象我们能用来解决这个问题.买东西不能看广告,要看疗效.究竟 Bridge 模式能解决我们的问题吗? 谁用谁知道.哈哈.