本文章的代码摘自Bishop的《C# 3.0 Design Patterns》
1.Composite模式的UML图
2. 相应的代码示例
public interface IComponent<T>
{
void Add(IComponent<T> c);
IComponent<T> Remove(T s);
string Display(int depth);
IComponent<T> Find(T s);
T Name { get; set; }
}
// The Component
public class Component<T> : IComponent<T>
{
public T Name { get; set; }
public Component(T name)
{
Name = name;
}
public void Add(IComponent<T> c)
{
Console.WriteLine("Cannot add to an item");
}
public IComponent<T> Remove(T s)
{
Console.WriteLine("Cannot remove directly");
return this;
}
public string Display(int depth)
{
return new String('-', depth) + Name + "\n";
}
public IComponent<T> Find(T s)
{
if (s.Equals(Name))
return this;
else
return null;
}
}
// The Composite
public class Composite<T> : IComponent<T>
{
List<IComponent<T>> list = null;
public T Name { get; set; }
public Composite(T name)
{
Name = name;
list = new List<IComponent<T>>();
}
public void Add(IComponent<T> c)
{
list.Add(c);
}
// Finds the item from a particular point in the structure
// and returns the composite from which it was removed
// If not found, return the point as given
public IComponent<T> Remove(T s)
{
holder = this;
IComponent<T> p = holder.Find(s);
if (holder != null)
{
(holder as Composite<T>).list.Remove(p);
return holder;
}
else
return this;
}
IComponent<T> holder = null;
// Recursively looks for an item
// Returns its reference or else null
public IComponent<T> Find(T s)
{
holder = this;
if (Name.Equals(s)) return this;
IComponent<T> found = null;
foreach (IComponent<T> c in list)
{
found = c.Find(s);
if (found != null)
break;
}
return found;
}
// Displays items in a format indicating their level in the composite structure
public string Display(int depth)
{
StringBuilder s = new StringBuilder(new String('-', depth));
s.Append("Set " + Name + " length :" + list.Count + "\n");
foreach (IComponent<T> component in list)
{
s.Append(component.Display(depth + 2));
}
return s.ToString();
}
}
它的神奇之处在于Composite中的List<IComponent<T>>。由于Component和Composite都继承自IComponent所以List中两者都可以存储从而形成一个复杂的树结构。
3.此模式解决的是什么问题?
Client可以根据实际情况构建相应的数据结构。也就是说这个模式可以处理这种变化。这是面向对象的优点。
4.上述代码的问题
仔细观察给的测试数据会发现如果要删除一个元素必须将引用定位在被删除元素的父节点。这个有点过于严格了。上述代码中的IComponent<T> holder = null;应该就是用来解决这个问题的,但是没有实现。在后来的校勘中作者修改了代码将holder去掉了当然这个问题还是没解决。holder的问题在于函数递归调用时使用的是不同集合对象的holder所以无法用来定位被删除元素的父节点。谁能解决此问题?