2-4设计模式之组合模式(Composite)

2.4.1 模式意图:

在处理树形结构数据时,通常必须区分叶节点和分支节点。这使代码更复杂,也更容易出错。组合模式模糊了叶节点和分支节点的概念,可以使叶节点和分支节点以单一对象的方式统一处理,且所有节点对象均具有相似的功能。

2.4.2 模式概念:

它属于结构型模式,将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

2.4.3 模式元素:

  • 节点抽象(CompsiteBase)
  • 叶子节点(Leaf)
  • 复合节点(Composite)

2.4.4 代码示例:

示例相对简单,就是一个树状的结构,一个主干,然后就是分支,每个分支可能是叶子节点,也可能是含有子分支的节点。

A.创建一个节点的抽象基类 ,也就是每个节点基类

    public abstract class CompsiteBase
    {
        protected string name;

        public CompsiteBase(string name)
        {
            this.name = name;
        }

        public abstract void Add(CompsiteBase c);
        public abstract void Remove(CompsiteBase c);
        public abstract void Display(int depth);
    }

B.叶子节点,也就是不含子节点的分支

public class Leaf : CompositeBase
{
    public Leaf(string name) : base(name) { }

    public override void Add(CompositeBase c)
    {
        Debug.Log("Cannot add to a leaf");
    }

    public override void Remove(CompositeBase c)
    {
        Debug.Log("Cannot remove from a leaf");
    }

    public override void Display(int depth)
    {
        Debug.Log(new string('-', depth) + name);
    }
}

C.含有子节点的分支

public class Composite : CompositeBase
{
    private List children = new List();

    public Composite(string name) : base(name) { }

    public override void Add(CompositeBase c)
    {
        children.Add(c);
    }

    public override void Remove(CompositeBase c)
    {
        children.Remove(c);
    }

    public override void Display(int depth)
    {
        Debug.Log(new String('-', depth) + name);

        foreach (CompositeBase composite in children)
        {
            compsite.Display(depth + 2);
        }
    }
}

示例调用

    void Start()
    {
        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"));

        comp.Add(comp2);

        root.Add(new Leaf("Leaf C"));

        Leaf leaf = new Leaf("Leaf D");
        root.Add(leaf);
        root.Remove(leaf);

        root.Display(1);
    }

2.4.5 写法对比:

2.4.6 模式分析:

通过CompositeBase接口来统一处理LeafComposite对象: Leaf对象直接执行请求,而Composite对象将请求以递归的方式向下传递到树结构的子节点。这使得类更易于实现、更改、测试和重用。

组合模式也分为安全模式透明模式

  • 安全模式:在抽象基类中没有提供 Add Remove等管理子节点的函数。
    优点:不必实现不需要的相关函数。
    缺点:需要区分叶子节点和含有子节点的分支,进行分别调用。
  • 透明模式:与安全模式相反,含有对应管理子节点的函数。
    优点:可以统一的调用。
    缺点:容易错误调用相关的管理函数而引发异常。

2.4.7 应用场景:

  • 整体部分的层次为树结构,且需要统一对待部分和整体对象。

2.4.8 小结:

当你发现需求是体现部分与整体层次结构时,以及你希望用户可以忽律组合对象与单个对象的不同,统一地使用组合结构中的所有对象,就可以考虑使用组合模式了。


更多设计模式详见:设计模式全家桶

发表评论