设计模式(2) ------------组合模式

本文详细介绍了组合模式的概念,以及如何通过透明和安全两种方式实现组合模式,旨在简化对象管理和提高代码复用性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.1.1 摘要

      在软件系统设计中,我们经常会遇到整体和部分的设计问题,例如为一家架构完善的公司设计系统时,我们在系统设计过程中应该更加注重这种整体和部分的关系(总部和分部的关系),这就是我们今天要介绍的组合模式(Composite)。

      组合模式(Composite)把对象构造成为一棵对象树,现在让我们简短回忆一下树的定义。

      树是一种数据结构,它是由n(n>=1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:

      每个结点有零个或多个子结点;

      每一个子结点只有一个父结点;

      没有前驱的结点为根结点;

      除了根结点外,每个子结点可以分为m个不相交的子树(参考维基百科);



  • 定义

        组合模式(Composite),将对象组合成树形结构以表示‘部分-整体’的层次关系(树状结构)。组合模式使得用户对单个对象和组合对象使用具有一致性。

 

  • 意图

        希望用户可以忽略单个对象和组合对象的区别,统一使用组合结构中的所有对象(封装变化的思想)。

 

  • 结构图

 

                                                       

图1组合模式(Composite)结构图

 

  • 参与者

        Component

        它是一个抽象角色,为对象的组合提供统一的接口。

        为其派生类提供默认的行为。

        通过该接口来访问和管理Child Components(节点后继)。

        通过该接口来访问Parent Components(节点前驱)。

 

        Leaf

        代表参加组合的叶子对象(叶子没有后继)。

        定义组成原始对象的行为。

 

        Composite

        定义非叶子对象的行为。

        实现Component中的孩子操作行为(如:Add(),Remove() 等)。

 

 

1.1.2 正文

      在我们学习组合模式(Composite)之前,让我们先讲解一下透明方式和安全方式。

      透明方式:在Component中声明所有用来管理子对象的方法,如Add()方法,Remove()方法及GetChild()方法,所有实现Component接口的子类都具备这些方法,这使得Component和子类具备一致的行为接口,使得对客户端无需区别树叶和树枝对象。

      大家可以回忆一下代理模式(Proxy)中,Proxy,RealSubject类和Subject接口具备一致的行为接口,从而使得被代理者对于客户端是透明的。

      正由于我们的Composite和Leaf都具备一致的接口行为,但我们知道Leaf不应该具有Add(),Remove()及GetChild()方法,因为我们叶子节点不能再添加和移除节点了。

      安全模式:在透明模式基础上把Component中声明所有用来管理子对象的方法移到Composite中,在Composite实现子对象的管理方法,那么Leaf就没有子对象管理方法,这使得Composite和Leaf的行为接口不一致,所以客户端在调用时要知道树叶和树枝对象存在。

 

                                       

图2透明方式的组合模式(Composite)结构图

 

                                        

图3安全方式的组合模式(Composite)结构图

 

      通过前面的介绍我们知道透明和安全方式组合模式(Composite)的区别在于是否在抽象接口Component中定义子对象的管理行为。现在让我们完成透明方式的组合模式(Composite)。

      以下示例代码演示透明方式的组合模式代码:

      首先我们定义一个抽象类Componet,在其中声明Add(),Remove()和Display()等子对象操作发法及初始化字段name的公共行为。

 

/// <summary>
/// The Component acts as abstract class.
/// </summary>
public abstract class Component
{
    protected string name;


    public Component()
    {
    }


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

    #region Methods

    public abstract Component Add(Component obj);
    public abstract void Remove(Component obj);
    public abstract void Display(int depth);

    #endregion

}

      接着我们定义Composite类继承于Component,增加_children保存Component对象的引用,从而建立起由Component到Composite的聚集关系(Has-a关系),并且实现Component抽象类中的抽象方法。

 

/// <summary>
/// The Composite acts as branch.
/// </summary>
public class Composite : Component
{
    private IList<Component> _childen = new List<Component>();


    public Composite()
    {
    }

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


    /// <summary>
    /// Adds the branch or leaf obj.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns></returns>
    public override Component Add(Component obj)
    {
        this._childen.Add(obj);
        return obj;
    }


    /// <summary>
    /// Removes the branch or leaf obj.
    /// </summary>
    /// <param name="obj">The obj.</param>
    public override void Remove(Component obj)
    {
        this._childen.Remove(obj);
    }


    /// <summary>
    /// Displays the tree's depth.
    /// </summary>
    /// <param name="depth">The depth.</param>
    public override void Display(int depth)
    {
        StringBuilder depthBuilder = new StringBuilder(new String('-', depth) + name);
        Console.WriteLine(depthBuilder);

        foreach (Component child in _childen)
        {
            child.Display(depth + 1);
        }
    }

}

      最后我们定义Leaf类它也是继承于Component,在其中我们实现Component定义的行为接口,这使得Composite和Leaf类具有统一的接口行为,但我们并没有在Leaf的行为方法中给出具体的实现,因为叶子节点并没有后继,所以没有必要实现Add()和Remove()等行为。

 

/// <summary>
/// The "Leaf" acts as Leaf.
/// </summary>
public class Leaf : Component
{

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


    public Leaf()
    {
    }


    /// <summary>
    /// Adds the branch or leaf obj.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns></returns>
    public override Component Add(Component obj)
    {
        throw new NotSupportedException();
    }


    /// <summary>
    /// Removes the branch or leaf obj.
    /// </summary>
    /// <param name="obj">The obj.</param>
    public override void Remove(Component obj)
    {
        throw new NotSupportedException();
    }


    /// <summary>
    /// Displays the tree's depth.
    /// </summary>
    /// <param name="depth">The depth.</param>
    public override void Display(int depth)
    {
        StringBuilder depthBuilder = new StringBuilder(new String('-', depth) + name);
        Console.WriteLine(depthBuilder);
    }
}

      我们定义一个工厂方法来创建Composite和Leaf对象,大家可以注意到在创建一个Component对象之后,我们调用子对象管理方法时,并不需要判断当前对象是由Composite类,还是有Leaf类创建得来,这就是透明方式的组合模式(Composite)。

public class Program
{
    static void Main(string[] args)
    {
        Client client = new Client();
        Component component = client.Get("root");
        Component componentA = component.Add(new Composite("BranchA"));
        componentA.Add(new Leaf("LeafA"));
        componentA.Add(new Leaf("LeafB"));
        Component componentB = component.Add(new Composite("BranchB"));

        component.Display(1);

        Console.ReadKey();
    }
}

composite3

图4输出结果

 

      前面例子给出了透明方式组合模式(Composite)的实现,我们在Component中声明了Add() 和Remove()操作子对象方法,使得Composite和Leaf类具备一致的行为接口,客户端可以正常调用Composite中的操作子对象方法,但如果客户端尝试调用Leaf中操作子对象方法时会抛出异常,因为叶子节点没有后继节点了,假设我们要实现安全方式组合模式(Composite)客户端在调用操作子对象方法时,需要判断当前对象是叶子节点或枝节点。

 

 

Component component = client.Get("root");

if (component is Composite)
{
    //// Implemention code.
}

 

 

      接下来让我们通过绘图程序实例,介绍安全方式的组合模式(Composite)的实现,首先我们定义一个抽象类DrawingProgramm,其角色为Component,然后再添加三个子类Shape,Triangle和Circle,它们的角色分别为:Composite,Leaf和Leaf。

      现在把子对象的管理方法都移到Shape类中,所以对客户端来说调用子对象时,它了解Shape、Triangle和Circle直接的区别。

 

      以下示例代码演示安全方式的组合模式代码:

      首先我们定义一个抽象类DrawingProgramming(即Componet),在其中声明Draw()及初始化字段_name的公共行为。

 

/// <summary>
/// The "DrawingProgramming" class acts as component.
/// </summary>
public abstract class DrawingProgramming
{
    protected string _name;
    public abstract void Draw();

    public DrawingProgramming(string name)
    {
        this._name = name;
    }
}

 

      接着我们定义Shape类继承于DrawingProgramming,增加_children保存DrawingProgramming对象的引用,也是建立起由DrawingProgramming到Shape的聚集关系(Has-a关系),大家要注意到安全方式的组合模式(Composite)对子对象的管理方法都移到Shape类(即Composite)中,使得Leaf和Composite的行为接口不一致。

 

/// <summary>
/// The "Shape" class acts as composite.
/// </summary>
public class Shape : DrawingProgramming
{

    IList<DrawingProgramming> _children = new List<DrawingProgramming>();


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

    #region DrawingProgramming 成员

    public override void Draw()
    {
        StringBuilder depthBuilder = new StringBuilder(_name);
        Console.WriteLine(depthBuilder);
        foreach (DrawingProgramming child in _children)
        {
            child.Draw();
        }
    }

    #endregion

    #region Methods

    public void Add(DrawingProgramming dp)
    {
        _children.Add(dp);
    }

    public void Remove(DrawingProgramming dp)
    {
        _children.Remove(dp);
    }

    #endregion
}

 

 

      最后我们定义Triangle和Circle类它也是继承于DrawingProgramming,在其中我们实现DrawingProgramming定义的Draw()行为,这使得Composite和Leaf类具有不一致的接口行为,这样我们可以避免在Leaf中实现没有必要地接口,从而使得我们设计符合SRP原则(对象职责单一原则)。

 

/// <summary>
/// The "Triangle" class acts as leaf.
/// </summary>
public class Triangle : DrawingProgramming
{

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

    #region DrawingProgramming 成员

    public override void Draw()
    {
        StringBuilder depthBuilder = new StringBuilder(_name);
        Console.WriteLine(depthBuilder);
    }

    #endregion
}


/// <summary>
/// The "Circle" class acts as leaf.
/// </summary>
public class Circle : DrawingProgramming
{
    public Circle(string name)
        : base(name)
    {

    }

    #region DrawingProgramming 成员

    public override void Draw()
    {
        StringBuilder depthBuilder = new StringBuilder(_name);
        Console.WriteLine(depthBuilder);
    }

    #endregion
}

 

 

  • 定义

        组合模式(Composite),将对象组合成树形结构以表示‘部分-整体’的层次关系(树状结构)。组合模式使得用户对单个对象和组合对象使用具有一致性。

 

  • 意图

        希望用户可以忽略单个对象和组合对象的区别,统一使用组合结构中的所有对象(封装变化的思想)。

 

  • 结构图

 

composite0

图1组合模式(Composite)结构图

 

  • 参与者

        Component

        它是一个抽象角色,为对象的组合提供统一的接口。

        为其派生类提供默认的行为。

        通过该接口来访问和管理Child Components(节点后继)。

        通过该接口来访问Parent Components(节点前驱)。

 

        Leaf

        代表参加组合的叶子对象(叶子没有后继)。

        定义组成原始对象的行为。

 

        Composite

        定义非叶子对象的行为。

        实现Component中的孩子操作行为(如:Add(),Remove() 等)。

 

 

1.1.2 正文

      在我们学习组合模式(Composite)之前,让我们先讲解一下透明方式和安全方式。

      透明方式:在Component中声明所有用来管理子对象的方法,如Add()方法,Remove()方法及GetChild()方法,所有实现Component接口的子类都具备这些方法,这使得Component和子类具备一致的行为接口,使得对客户端无需区别树叶和树枝对象。

      大家可以回忆一下代理模式(Proxy)中,Proxy,RealSubject类和Subject接口具备一致的行为接口,从而使得被代理者对于客户端是透明的。

      正由于我们的Composite和Leaf都具备一致的接口行为,但我们知道Leaf不应该具有Add(),Remove()及GetChild()方法,因为我们叶子节点不能再添加和移除节点了。

      安全模式:在透明模式基础上把Component中声明所有用来管理子对象的方法移到Composite中,在Composite实现子对象的管理方法,那么Leaf就没有子对象管理方法,这使得Composite和Leaf的行为接口不一致,所以客户端在调用时要知道树叶和树枝对象存在。

 

composite1

图2透明方式的组合模式(Composite)结构图

 

 composite2

图3安全方式的组合模式(Composite)结构图

 

      通过前面的介绍我们知道透明和安全方式组合模式(Composite)的区别在于是否在抽象接口Component中定义子对象的管理行为。现在让我们完成透明方式的组合模式(Composite)。

      以下示例代码演示透明方式的组合模式代码:

      首先我们定义一个抽象类Componet,在其中声明Add(),Remove()和Display()等子对象操作发法及初始化字段name的公共行为。

 

/// <summary>
/// The Component acts as abstract class.
/// </summary>
public abstract class Component
{
    protected string name;


    public Component()
    {
    }


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

    #region Methods

    public abstract Component Add(Component obj);
    public abstract void Remove(Component obj);
    public abstract void Display(int depth);

    #endregion

}

      接着我们定义Composite类继承于Component,增加_children保存Component对象的引用,从而建立起由Component到Composite的聚集关系(Has-a关系),并且实现Component抽象类中的抽象方法。

 

/// <summary>
/// The Composite acts as branch.
/// </summary>
public class Composite : Component
{
    private IList<Component> _childen = new List<Component>();


    public Composite()
    {
    }

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


    /// <summary>
    /// Adds the branch or leaf obj.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns></returns>
    public override Component Add(Component obj)
    {
        this._childen.Add(obj);
        return obj;
    }


    /// <summary>
    /// Removes the branch or leaf obj.
    /// </summary>
    /// <param name="obj">The obj.</param>
    public override void Remove(Component obj)
    {
        this._childen.Remove(obj);
    }


    /// <summary>
    /// Displays the tree's depth.
    /// </summary>
    /// <param name="depth">The depth.</param>
    public override void Display(int depth)
    {
        StringBuilder depthBuilder = new StringBuilder(new String('-', depth) + name);
        Console.WriteLine(depthBuilder);

        foreach (Component child in _childen)
        {
            child.Display(depth + 1);
        }
    }

}

      最后我们定义Leaf类它也是继承于Component,在其中我们实现Component定义的行为接口,这使得Composite和Leaf类具有统一的接口行为,但我们并没有在Leaf的行为方法中给出具体的实现,因为叶子节点并没有后继,所以没有必要实现Add()和Remove()等行为。

 

/// <summary>
/// The "Leaf" acts as Leaf.
/// </summary>
public class Leaf : Component
{

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


    public Leaf()
    {
    }


    /// <summary>
    /// Adds the branch or leaf obj.
    /// </summary>
    /// <param name="obj">The obj.</param>
    /// <returns></returns>
    public override Component Add(Component obj)
    {
        throw new NotSupportedException();
    }


    /// <summary>
    /// Removes the branch or leaf obj.
    /// </summary>
    /// <param name="obj">The obj.</param>
    public override void Remove(Component obj)
    {
        throw new NotSupportedException();
    }


    /// <summary>
    /// Displays the tree's depth.
    /// </summary>
    /// <param name="depth">The depth.</param>
    public override void Display(int depth)
    {
        StringBuilder depthBuilder = new StringBuilder(new String('-', depth) + name);
        Console.WriteLine(depthBuilder);
    }
}

      我们定义一个工厂方法来创建Composite和Leaf对象,大家可以注意到在创建一个Component对象之后,我们调用子对象管理方法时,并不需要判断当前对象是由Composite类,还是有Leaf类创建得来,这就是透明方式的组合模式(Composite)。

public class Program
{
    static void Main(string[] args)
    {
        Client client = new Client();
        Component component = client.Get("root");
        Component componentA = component.Add(new Composite("BranchA"));
        componentA.Add(new Leaf("LeafA"));
        componentA.Add(new Leaf("LeafB"));
        Component componentB = component.Add(new Composite("BranchB"));

        component.Display(1);

        Console.ReadKey();
    }
}

composite3

图4输出结果

 

      前面例子给出了透明方式组合模式(Composite)的实现,我们在Component中声明了Add() 和Remove()操作子对象方法,使得Composite和Leaf类具备一致的行为接口,客户端可以正常调用Composite中的操作子对象方法,但如果客户端尝试调用Leaf中操作子对象方法时会抛出异常,因为叶子节点没有后继节点了,假设我们要实现安全方式组合模式(Composite)客户端在调用操作子对象方法时,需要判断当前对象是叶子节点或枝节点。

 

 

Component component = client.Get("root");

if (component is Composite)
{
    //// Implemention code.
}

 

 

      接下来让我们通过绘图程序实例,介绍安全方式的组合模式(Composite)的实现,首先我们定义一个抽象类DrawingProgramm,其角色为Component,然后再添加三个子类Shape,Triangle和Circle,它们的角色分别为:Composite,Leaf和Leaf。

      现在把子对象的管理方法都移到Shape类中,所以对客户端来说调用子对象时,它了解Shape、Triangle和Circle直接的区别。

 

      以下示例代码演示安全方式的组合模式代码:

      首先我们定义一个抽象类DrawingProgramming(即Componet),在其中声明Draw()及初始化字段_name的公共行为。

 

/// <summary>
/// The "DrawingProgramming" class acts as component.
/// </summary>
public abstract class DrawingProgramming
{
    protected string _name;
    public abstract void Draw();

    public DrawingProgramming(string name)
    {
        this._name = name;
    }
}

 

      接着我们定义Shape类继承于DrawingProgramming,增加_children保存DrawingProgramming对象的引用,也是建立起由DrawingProgramming到Shape的聚集关系(Has-a关系),大家要注意到安全方式的组合模式(Composite)对子对象的管理方法都移到Shape类(即Composite)中,使得Leaf和Composite的行为接口不一致。

 

/// <summary>
/// The "Shape" class acts as composite.
/// </summary>
public class Shape : DrawingProgramming
{

    IList<DrawingProgramming> _children = new List<DrawingProgramming>();


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

    #region DrawingProgramming 成员

    public override void Draw()
    {
        StringBuilder depthBuilder = new StringBuilder(_name);
        Console.WriteLine(depthBuilder);
        foreach (DrawingProgramming child in _children)
        {
            child.Draw();
        }
    }

    #endregion

    #region Methods

    public void Add(DrawingProgramming dp)
    {
        _children.Add(dp);
    }

    public void Remove(DrawingProgramming dp)
    {
        _children.Remove(dp);
    }

    #endregion
}

 

 

      最后我们定义Triangle和Circle类它也是继承于DrawingProgramming,在其中我们实现DrawingProgramming定义的Draw()行为,这使得Composite和Leaf类具有不一致的接口行为,这样我们可以避免在Leaf中实现没有必要地接口,从而使得我们设计符合SRP原则(对象职责单一原则)。

 

/// <summary>
/// The "Triangle" class acts as leaf.
/// </summary>
public class Triangle : DrawingProgramming
{

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

    #region DrawingProgramming 成员

    public override void Draw()
    {
        StringBuilder depthBuilder = new StringBuilder(_name);
        Console.WriteLine(depthBuilder);
    }

    #endregion
}


/// <summary>
/// The "Circle" class acts as leaf.
/// </summary>
public class Circle : DrawingProgramming
{
    public Circle(string name)
        : base(name)
    {

    }

    #region DrawingProgramming 成员

    public override void Draw()
    {
        StringBuilder depthBuilder = new StringBuilder(_name);
        Console.WriteLine(depthBuilder);
    }

    #endregion
}

 

 转载自:http://www.cnblogs.com/rush/archive/2011/07/10/2102288.html

 



 


<think>嗯,用户想了解结构化思维(SCoT)的提示词或应用方法,特别是在AI或编程领域。首先,我需要确认自己对SCoT的理解是否正确。SCoTChain-of-ThoughtCoT)的扩展,强调结构化的分步推理,可能涉及分解问题、逻辑流程等。 用户可能需要具体的例子,比如在数学问题、编程任务中的应用。然后,我要回想相关的研究或应用案例,是否有论文或实际项目中使用过SCoT。比如,Google Research提到过结构化思维在复杂问题中的应用,可能需要引用这个来源。 接下来,应该考虑用户的使用场景。用户可能在开发AI模型,或者希望优化现有提示词的效果。他们可能遇到需要模型处理复杂逻辑的问题,需要更结构化的方法。此外,用户可能对如何设计有效的提示词感兴趣,比如分步指导、模板示例等。 还要考虑用户的身份,可能是AI研究人员、开发者或学生。不同身份可能需要不同深度的解释。比如开发者可能需要实际代码示例,而学生可能需要理论上的解释。 用户需求可能包括:SCoT的基本概念,与普通CoT的区别,实际应用案例,如何构建有效的SCoT提示词,以及在编程中的具体例子。同时,用户可能希望了解如何评估SCoT的效果,或者在不同任务中的适用性。 需要确保回答结构清晰,分点说明,并附上示例。比如,分步骤解释SCoT的应用方法,每个方法举一个例子,可能涉及数学问题解决、代码生成、逻辑推理等。同时,生成相关问题,帮助用户进一步探索。 最后,检查是否有遗漏,比如是否覆盖了用户可能关心的优化方法、常见挑战,或者与其他技术的对比。确保引用正确的文献,比如提到的Google Research的例子,以及可能的相关研究。</think>以下是对结构化思维(Structured Chain-of-Thought,SCoT)的详细解析及应用方法: # 结构化思维(SCoT核心方法 SCoT通过显式结构化推理路径提升AI模型复杂任务处理能力,其关键特征包括: 1. **多层级分解**:将问题拆解为$problem \rightarrow subproblems \rightarrow steps$的树状结构 2. **逻辑符号化**:使用数学符号标记推理节点,如$P_1 \Rightarrow C_1$表示命题推导 3. **路径验证**:通过反向检查$Verify(C_n, Premise)$确保推理连贯性 ## 典型应用场景 ### 1. 复杂数学问题求解 **提示词示例**: ``` 请分步解决:当$x \to 0$时,比较$\sqrt{1+2x}-(1+x)$与$x^2$的无穷小阶数。 要求: 1. 展开泰勒公式到合适阶数 2. 计算分子差值表达式 3. 进行系数比较 ``` **模型响应示例**: $$设f(x)=\sqrt{1+2x}-(1+x)$$ $$泰勒展开:\sqrt{1+2x} ≈ 1 + x - \frac{x^2}{2} + o(x^2)$$ $$差值f(x)(1+x-\frac{x^2}{2}) -1 -x = -\frac{x^2}{2}$$ $$因此f(x) \sim -\frac{1}{2}x^2,即与x^2同阶$$ ### 2. 代码生成优化 **提示词模板**: ```python # 任务:实现{功能描述} # 约束条件: 1. 时间复杂度不超过O(n log n) 2. 内存占用优化 3. 处理边界情况:{列举具体场景} 分步要求: Step 1: 分析问题特征,选择合适算法 Step 2: 设计数据结构草图 Step 3: 编写伪代码验证逻辑 Step 4: 转换为正式代码 ``` ### 3. 逻辑推理增强 在知识问答中采用三段论结构: ``` 前提识别:{事实1} ∧ {事实2} 推理规则:∀x(P(x)→Q(x)) 结论推导:∴ {最终结论} [^1] ``` # 实践建议 1. **显式结构标记**:使用数字编号/字母标记推理步骤 2. **中间验证点**:插入`Check: 当前结果是否满足条件X?` 3. **多视角分析**:对关键步骤提供`Alternative Approach:...`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值