将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象好人组合对象的使用具有一致性。
//Component为组合中的对象声明接口,在适当情况下,实现所有类共有接口的默认行为。
//声明一个借口用于访问和管理Component的子部件
abstractclass Component
{
protected string name;
public Component(string name)
{
this.name = name;
}
//使用Add和Remove来提供增加或删除树叶或树枝的功能
public abstract void Add(Component c);
public abstract void Remove(Component c);
public abstract void Display(int depth);
};
//Leaf在组合中表示叶节点对象,叶节点没有子节点
class Leaf:Component
{
public Leaf(string name) :base(name)
{}
public override void Add(Component c)
{
//叶子节点无法再增加分支和树叶,所以Add和Remove方法实现也没有意义,但这样可以消除叶节点和枝节点对象在抽象层次的区别,他们具有完全一致的接口
Console.WriteLine("Cannot add toa leaf");
}
public override void Remove(Component c)
{
Console.WriteLine("Cannot add toa leaf");
}
public override void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name); //这里指 depth个 ‘-’, 后跟一个名字
}
};
//枝节点,存储子部件
class Composite : Component
{
//一个子对象集合存储其下的枝节点和叶节点
private List<Component> children = new List<Component>();
public Composite(string name) :base(name)
{}
public override void Add(Component c)
{
children.Add(c);
}
public abstract void Remove(Component c)
{
children.Remove(c);
}
public abstract void Display(int depth)
{
Console.WriteLine(new string('-', depth) + name);
foreach (Component component inchildren)
{
component.Display(depth + 2);
}
}
};
//客户端
void main()
{
Composite root = new Composite("root");
root.Add(new Leaf("Leaf A"));
root.Add(new Leaf("Leaf B"));
Composite comp = new Composite("Composite X");
comp.Add(new Leaf("Leaf XA"));
comp.Add(new Leaf("Leaf XB"));
root.Add(comp);
Composite comp2 = new Composite("Composite XY");
comp2.Add(new Leaf("Leaf XYA"));
comp2.Add(new Leaf("Leaf XYB"));
root.Add(comp2);
root.Add(new Leaf("Leaf C"));
Leaf leaf = new Leaf("Leaf D");
root.Add(leaf);
root.Remove(leaf);
root.Display(1);
}
运行结果如下:
在叶节点中实现Add和Remove功能是没有意义的,我们可以在Component中去除这两个功能,而在Composite中单独添加这两个功能,这叫安全模式,当然这样子有好也有不好的地方。
何时使用?
当你发现需求中是体现部分与整体层次的结构时候,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时。
下面,给出一个具体的例子,关于总公司、公司部分、分公司的公司管理系统:
abstractclass Company
{
private string name;
public Company(string name)
{
this.name = name;
}
public abstract void Add(Company c);
public abstract void Remove(Company c);
public abstract void Display(int depth);
public abstract void Duty(Company c); //职责
};
class ConcretCompany : Company
{
private List<Company> children = newList<Company>();
public ConcretCompany(string name) :base(name)
{}
public abstract void Add(Company c)
{
children.Add(c);
}
public abstract void Remove(Company c)
{
children.Remove(c);
}
public abstract void Display(int depth)
{
Console.WriteLine(new string('-', depth) + name);
foreach(Component component in children)
{
component.Display(depth + 2);
}
}
public abstract void Duty(Company c)
{
foreach(Component component in children)
{
component.Duty();
}
}
};
//人力资源部
class HRDep :Company
{
public HRDep(string name) :base(name)
{}
public abstract void Add(Company c)
{}
public abstract void Remove(Company c)
{}
public abstract void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
}
public abstract void Duty(Company c)
{
Console.WriteLine("{0} 招聘", name);
}
};
//其他部门
class OTDep :Company
{
public OTDep(string name) :base(name)
{}
public abstract void Add(Company c)
{}
public abstract void Remove(Company c)
{}
public abstract void Display(int depth)
{
Console.WriteLine(new String('-', depth) + name);
}
public abstract void Duty(Company c)
{
Console.WriteLine("{0} 其他", name);
}
};
void main()
{
//...
}
组合模式这样就定义了包含公司的部门和分公司。
基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,不断递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象了
让客户可以一致的使用组合结构和单个对象