组合模式的定义
组合模式允许你将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象以及对象的组合。
组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。
- Component抽象构件
定义参加组合对象的共同方法和属性,可以定义一些默认的行为或属性。
- Leaf叶子构件
叶子对象,其下再也没有其他的分支,也就是遍历的最小单位。
- Composite树枝构件
树枝对象,它的作业是组合树枝节点和叶子节点形成一个树形结构。
具体代码如下:
View Code
namespace ConsoleApplication1 { /// <summary> /// 抽象构件 /// </summary> public abstract class Component { //个体和整体都具有的共享 public virtual void doSomething() { // } } /// <summary> /// 树枝构件 /// </summary> public class Composite : Component { //构件容器 private List<Component> componentList = new List<Component>(); //增加一个叶子构件或树枝构件 public void Add(Component component) { componentList.Add(component); } //删除一个叶子构件或树枝构件 public void remove(Component component) { componentList.Remove(component); } //获取分支下的所有叶子构件和树枝构件 public List<Component> getChildren() { return this.componentList; } public override void doSomething() { } } /// <summary> /// 树叶构件 /// </summary> public class Leaf : Component { //覆盖父类的方法 public override void doSomething() { } } class Program { static void Main(string[] args) { //创建一个根节点 Composite root = new Composite(); root.doSomething(); //创建一个树枝构件 Composite branch = new Composite(); //创建一个叶子节点 Leaf leaf = new Leaf(); //建立整体 root.Add(branch); branch.Add(leaf); Console.ReadLine(); } static void display(Composite root) { foreach (Component c in root.getChildren()) { if (c is Leaf) { //叶子节点 c.doSomething(); } else { //树枝节点 display((Composite)c); } } } } }
组合模式的优缺点
优点:
- 组合模式使得客户端代码可以一致地处理对象和对象容器,无需关系处理的单个对象,还是组合的对象容器。
- 将”客户代码与复杂的对象容器结构“解耦。
- 可以更容易地往组合对象中加入新的构件。
缺点:使得设计更加复杂。客户端需要花更多时间理清类之间的层次关系。(这个是几乎所有设计模式所面临的问题)。
注意的问题:
- 有时候系统需要遍历一个树枝结构的子构件很多次,这时候可以考虑把遍历子构件的结构存储在父构件里面作为缓存。
- 客户端尽量不要直接调用树叶类中的方法(在我上面实现就是这样的,创建的是一个树枝的具体对象,应该使用Graphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");),而是借用其父类(Graphics)的多态性完成调用,这样可以增加代码的复用性。
组合模式的使用场景
在以下情况下应该考虑使用组合模式:
- 需要表示一个对象整体或部分的层次结构。
- 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。