设计模式中,讲了一个组合模式,并给出了例子,但是应用中还是有一些不方便的
比如,树的遍历与查找,我最近在一个程序中遇到了一个树形问题,使用了组合模式,但是查找节点的时候,遇到了一点困难,
所以想一个办法来解决,就是使用hash表的方法来解决,
上下文(程序中使用的是.net framework1.1),为了兼容性,所以没有使用泛型:-<
需求
1.实现一个倒置的树,能从一个节点,找到他的父节点,及他的子节点(个数没有限制)
2.能快速地查找树中的任意一个节点,
3.能判断出一个节点是否从属于另一个节点,
解决的步骤
1.构造树
2.在结点类中声明一个静态的hashtable表,来放置节点
3.将树中的所有节点放在hashtable中
(每一个节点,都有一个唯一的值,由于是从数据库中取出的数据,所以每一条数据的主键就可以放到hashtable中),
这个类的好处,用一个类的静态变量来存储所有的节点,用hashtable中的查找算法,取代了树的查找,
但是有一个坏处这个树在应用中只能实例化一次,而不能多次实例化,为什么呢?
因为类中用来实现查找的hashtable是一个静态变量,这个变量不会释放自己,所以多次实例化,
而其中的无素不变,可能会在使用这程中出现问题,由于我使用的上下文中不存在这种情况,
所以我就可以安心的使用,这样一个类
有了需求就可以写测试了
以下是测试代码
[TestFixture]
public class TestNode
{
private AbstractNode root;
private AbstractNode ceo;
private AbstractNode market;
private AbstractNode product;
[SetUp]
public void InitTree()
{
root = new AbstractNode(null,"root");
ceo = new AbstractNode(root,"ceo");
market = new AbstractNode(ceo,"market");
product = new AbstractNode(ceo,"product");
for (int i = 8; i < 12; i++)
{
AbstractNode ab = new AbstractNode(market,i.ToString());
market.AddChild(ab);
}
for (int i = 0; i < 3; i++)
{
AbstractNode ab = new AbstractNode(product,i.ToString());
product.AddChild(ab);
}
root.AddChild(ceo);
ceo.AddChild(product);
ceo.AddChild(market);
}
[Test]
public void TestHasChild()
{
Assert.IsTrue(root.HasChild(market),"root must have market");
AbstractNode ab=new AbstractNode("9");
Assert.IsTrue(root.HasChild(ab), "9 is under market");
Assert.IsFalse(product.HasChild(ab), "9 is under market");
}
[Test]
public void TestChildPath()
{
AbstractNode ab = new AbstractNode("9");
Queue path = root.FindChild(ab);
Assert.IsTrue(path.Count > 0, "9 shold has a parent");
Assert.IsTrue(path.Count == 3, "deepth is 2");
int levelcount = path.Count;
while (path.Count > 0)
{
AbstractNode pathab = path.Dequeue() as AbstractNode;
if (pathab == null)
LogHelper.LogIt("it is the head");
else
LogHelper.LogIt("this is the :" + levelcount.ToString() + " node and its key is: " + pathab.Key);
levelcount++;
}
}
}
有了测试代码,可以设计一个类了,这个类是模式的抽象(组合模式)public class TestNode
{
private AbstractNode root;
private AbstractNode ceo;
private AbstractNode market;
private AbstractNode product;
[SetUp]
public void InitTree()
{
root = new AbstractNode(null,"root");
ceo = new AbstractNode(root,"ceo");
market = new AbstractNode(ceo,"market");
product = new AbstractNode(ceo,"product");
for (int i = 8; i < 12; i++)
{
AbstractNode ab = new AbstractNode(market,i.ToString());
market.AddChild(ab);
}
for (int i = 0; i < 3; i++)
{
AbstractNode ab = new AbstractNode(product,i.ToString());
product.AddChild(ab);
}
root.AddChild(ceo);
ceo.AddChild(product);
ceo.AddChild(market);
}
[Test]
public void TestHasChild()
{
Assert.IsTrue(root.HasChild(market),"root must have market");
AbstractNode ab=new AbstractNode("9");
Assert.IsTrue(root.HasChild(ab), "9 is under market");
Assert.IsFalse(product.HasChild(ab), "9 is under market");
}
[Test]
public void TestChildPath()
{
AbstractNode ab = new AbstractNode("9");
Queue path = root.FindChild(ab);
Assert.IsTrue(path.Count > 0, "9 shold has a parent");
Assert.IsTrue(path.Count == 3, "deepth is 2");
int levelcount = path.Count;
while (path.Count > 0)
{
AbstractNode pathab = path.Dequeue() as AbstractNode;
if (pathab == null)
LogHelper.LogIt("it is the head");
else
LogHelper.LogIt("this is the :" + levelcount.ToString() + " node and its key is: " + pathab.Key);
levelcount++;
}
}
}
using System;
using System.Text;
using System.Collections;
namespace cdtest
{
public class AbstractNode
{
public AbstractNode()
{
childear = new ArrayList();
childpath = new Queue();
}
public AbstractNode(string pkey)
: this()
{
this.key = pkey;
}
public AbstractNode(AbstractNode pparent, string pkey)
: this(pkey)
{
parent = pparent;
if (pparent != null)
pparent.AddChild(this);
}
/// <summary>
/// store level
/// </summary>
private int level;
/// <summary>
/// used to store the key and object
/// </summary>
protected static Hashtable hs=new Hashtable();
/// <summary>
/// store child
/// </summary>
private ArrayList childear;
/// <summary>
/// store parent
/// </summary>
private AbstractNode parent;
/// <summary>
/// store key
/// </summary>
private string key;
/// <summary>
/// store the path to the child
/// </summary>
private Queue childpath;
/// <summary>
/// node level
/// </summary>
public int Level
{
get
{
return level;
}
set
{
level = value;
}
}
/// <summary>
/// node parent
/// </summary>
public AbstractNode Parent
{
get
{
return parent;
}
}
/// <summary>
/// key of this node
/// </summary>
public String Key
{
get
{
return key;
}
set
{
key = value;
}
}
public Hashtable Nodes
{
get
{
return hs;
}
}
/// <summary>
/// has child or not
/// </summary>
public bool IsLeaf
{
get
{
return Nodes.Count == 0;
}
}
public IEnumerator GetChild()
{
return childear.GetEnumerator();
}
public void AddChild(AbstractNode childnode)
{
childear.Add(childnode);
if (!hs.ContainsKey(childnode.Key))
{
childnode.Level = this.level + 1;
hs.Add(childnode.key, childnode);
}
}
public bool HasChild(AbstractNode pchild)
{
if (pchild.Key == this.Key)
return true;
bool found=false;
AbstractNode subordinates = null;
IEnumerator ienu = GetChild();
while (!found&& ienu.MoveNext())
{
subordinates = ienu.Current as AbstractNode;
found = subordinates.HasChild(pchild);
}
return found;
}
public Queue FindChild(AbstractNode pchild)
{
AbstractNode ab = Nodes[pchild.Key] as AbstractNode;
while (ab != null)
{
AbstractNode parentab = ab.Parent;
//we use null as node root
if (parentab != null)
{
childpath.Enqueue(parentab);
}
ab = parentab;
}
return childpath;
}
}
}
有了模式的抽象,就可以以到现实中的例子做实验了,如部门,及员工using System.Text;
using System.Collections;
namespace cdtest
{
public class AbstractNode
{
public AbstractNode()
{
childear = new ArrayList();
childpath = new Queue();
}
public AbstractNode(string pkey)
: this()
{
this.key = pkey;
}
public AbstractNode(AbstractNode pparent, string pkey)
: this(pkey)
{
parent = pparent;
if (pparent != null)
pparent.AddChild(this);
}
/// <summary>
/// store level
/// </summary>
private int level;
/// <summary>
/// used to store the key and object
/// </summary>
protected static Hashtable hs=new Hashtable();
/// <summary>
/// store child
/// </summary>
private ArrayList childear;
/// <summary>
/// store parent
/// </summary>
private AbstractNode parent;
/// <summary>
/// store key
/// </summary>
private string key;
/// <summary>
/// store the path to the child
/// </summary>
private Queue childpath;
/// <summary>
/// node level
/// </summary>
public int Level
{
get
{
return level;
}
set
{
level = value;
}
}
/// <summary>
/// node parent
/// </summary>
public AbstractNode Parent
{
get
{
return parent;
}
}
/// <summary>
/// key of this node
/// </summary>
public String Key
{
get
{
return key;
}
set
{
key = value;
}
}
public Hashtable Nodes
{
get
{
return hs;
}
}
/// <summary>
/// has child or not
/// </summary>
public bool IsLeaf
{
get
{
return Nodes.Count == 0;
}
}
public IEnumerator GetChild()
{
return childear.GetEnumerator();
}
public void AddChild(AbstractNode childnode)
{
childear.Add(childnode);
if (!hs.ContainsKey(childnode.Key))
{
childnode.Level = this.level + 1;
hs.Add(childnode.key, childnode);
}
}
public bool HasChild(AbstractNode pchild)
{
if (pchild.Key == this.Key)
return true;
bool found=false;
AbstractNode subordinates = null;
IEnumerator ienu = GetChild();
while (!found&& ienu.MoveNext())
{
subordinates = ienu.Current as AbstractNode;
found = subordinates.HasChild(pchild);
}
return found;
}
public Queue FindChild(AbstractNode pchild)
{
AbstractNode ab = Nodes[pchild.Key] as AbstractNode;
while (ab != null)
{
AbstractNode parentab = ab.Parent;
//we use null as node root
if (parentab != null)
{
childpath.Enqueue(parentab);
}
ab = parentab;
}
return childpath;
}
}
}
部门下还可以细分部门,员工下边还可管理员工,等等
代码比较长,不贴了
有了现实中的例子,那么我们就可以应用的不同的应用程序中去了
如:使用数据库技术存储的DBDepartment,或者使用Xml文件存储的XmlDepartment
DBDepartment:Department
XmlDepartment:Department
有兴趣的朋友,可以看看全部代码