组合模式(Composite Pattern)

1.组合模式

1.1 定义

将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象以及对象的组合。
在这里插入图片描述

1.2 使用场景

在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象在功能上区别,导致在操作过程中必须区分简单对象和复合对象,这样就会导致客户调用带来不必要的麻烦,然而作为客户,它们希望能够始终一致地对待简单对象和复合对象。然而组合模式就是解决这样的问题。下面让我们看看组合模式是怎样解决这个问题的。

2.组合模式结构

在这里插入图片描述

  • 组件(Component):接口描述了树中简单项目和复杂项目所共有的操作。
  • 叶节点(Leaf):是树的基本结构, 它不包含子项目。一般情况下, 叶节点最终会完成大部分的实际工作, 因为它们无法将工作指派给其他部分。
  • 容器(Container):——又名 “组合 (Composite)”——是包含叶节点或其他容器等子项目的单位。 容器不知道其子项目所属的具体类, 它只通过通用的组件接口与其子项目交互。容器接收到请求后会将工作分配给自己的子项目, 处理中间结果, 然后将最终结果返回给客户端。
  • 客户端(Client) :通过组件接口与所有项目交互。 因此, 客户端能以相同方式与树状结构中的简单或复杂项目交互。

3.UML类图

3.1 透明式的组合模式类图

在这里插入图片描述

3.2 安全式组合模式的类图

在这里插入图片描述

4.具体实现

4.1 透明式的组合模式

组件(Component):

/// <summary>
/// 图形抽象类
/// </summary>
public abstract class Graphics
{
    public string Name {get; set;}
    public Graphics(string name)
    {
        Name = name;
    }

    public abstract void Draw();
    public abstract void Add(Graphics graphics);
    public abstract void Remove(Graphics graphics);
}

叶节点(Leaf):

/// <summary>
/// 简单图形类——线
/// </summary>
public class Line : Graphics
{
    public Line(string name) : base(name)
    { }

    // 重写父类抽象方法
    public override void Draw()
    {
        Console.WriteLine("画  " + Name);
    }

    // 因为简单图形在添加或移除其他图形,所以简单图形Add或Remove方法没有任何意义
    // 如果客户端调用了简单图形的Add或Remove方法将会在运行时抛出异常
    // 我们可以在客户端捕获该类移除并处理
    public override void Add(Graphics graphics)
    {
        throw new Exception("不能向简单图形Line添加其他图形");
    }

    public override void Remove(Graphics graphics)
    {
        throw new Exception("不能向简单图形Line移除其他图形");
    }
}

/// <summary>
/// 简单图形类——圆
/// </summary>
public class Circle : Graphics
{
    public Circle(string name)
        : base(name)
    { }

    // 重写父类抽象方法
    public override void Draw()
    {
        Console.WriteLine("画  " + Name);
    }

    public override void Add(Graphics g)
    {
        throw new Exception("不能向简单图形Circle添加其他图形");
    }
    public override void Remove(Graphics g)
    {
        throw new Exception("不能向简单图形Circle移除其他图形");
    }
}

容器(Container):

/// <summary>
/// 复杂图形,由一些简单图形组成,这里假设该复杂图形由一个圆两条线组成的复杂图形
/// </summary>
public class ComplexGraphics : Graphics
{
    private List<Graphics> complexGraphicsList = new List<Graphics>();

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

    /// <summary>
    /// 复杂图形的画法
    /// </summary>
    public override void Draw()
    {          
        foreach (Graphics g in complexGraphicsList)
        {
            g.Draw();
        }
    }

    public override void Add(Graphics g)
    {
        complexGraphicsList.Add(g);
    }
    public override void Remove(Graphics g)
    {
        complexGraphicsList.Remove(g);
    }
}

客户端(Client) :

ComplexGraphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
complexGraphics.Add(new Line("线段A"));
 ComplexGraphics CompositeCG = new ComplexGraphics("一个圆和一条线组成的复杂图形");
 CompositeCG.Add(new Circle("圆"));
 CompositeCG.Add(new Circle("线段B"));
 complexGraphics.Add(CompositeCG);
 Line l = new Line("线段C");
 complexGraphics.Add(l);

 // 显示复杂图形的画法
 Console.WriteLine("复杂图形的绘制如下:");
 complexGraphics.Draw();
 Console.WriteLine("复杂图形绘制完成");
 Console.WriteLine();

 // 移除一个组件再显示复杂图形的画法
 complexGraphics.Remove(l);
 Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
 complexGraphics.Draw();
 Console.WriteLine("复杂图形绘制完成");

复杂图形的绘制如下:
画 线段A
画 圆
画 线段B
画 线段C
复杂图形绘制完成
移除线段C后,复杂图形的绘制如下:
画 线段A
画 圆
画 线段B
复杂图形绘制完成

4.2 安全式组合模式

此方式实现的组合模式把管理子对象的方法声明在树枝构件ComplexGraphics类中

/// 此方式实现的组合模式把管理子对象的方法声明在树枝构件ComplexGraphics类中
/// 这样如果叶子节点Line、Circle使用了Add或Remove方法时,就能在编译期间出现错误
/// 但这种方式虽然解决了透明式组合模式的问题,但是它使得叶子节点和树枝构件具有不一样的接口。
/// 所以这两种方式实现的组合模式各有优缺点,具体使用哪个,可以根据问题的实际情况而定
class Client
{
    static void Main(string[] args)
    {
        ComplexGraphics complexGraphics = new ComplexGraphics("一个复杂图形和两条线段组成的复杂图形");
        complexGraphics.Add(new Line("线段A"));
        ComplexGraphics CompositeCG = new ComplexGraphics("一个圆和一条线组成的复杂图形");
        CompositeCG.Add(new Circle("圆"));
        CompositeCG.Add(new Circle("线段B"));
        complexGraphics.Add(CompositeCG);
        Line l = new Line("线段C");
        complexGraphics.Add(l);

        // 显示复杂图形的画法
        Console.WriteLine("复杂图形的绘制如下:");
        Console.WriteLine("---------------------");
        complexGraphics.Draw();
        Console.WriteLine("复杂图形绘制完成");
        Console.WriteLine("---------------------");
        Console.WriteLine();

        // 移除一个组件再显示复杂图形的画法
        complexGraphics.Remove(l);
        Console.WriteLine("移除线段C后,复杂图形的绘制如下:");
        Console.WriteLine("---------------------");
        complexGraphics.Draw();
        Console.WriteLine("复杂图形绘制完成");
        Console.WriteLine("---------------------");
        Console.Read();
    }
}

/// <summary>
/// 图形抽象类,
/// </summary>
public abstract class Graphics
{
    public string Name { get; set; }
    public Graphics(string name)
    {
        this.Name = name;
    }

    public abstract void Draw();
    // 移除了Add和Remove方法
    // 把管理子对象的方法放到了ComplexGraphics类中进行管理
    // 因为这些方法只在复杂图形中才有意义
}

/// <summary>
/// 简单图形类——线
/// </summary>
public class Line : Graphics
{
    public Line(string name)
        : base(name)
    { }

    // 重写父类抽象方法
    public override void Draw()
    {
        Console.WriteLine("画  " + Name);
    }
}

/// <summary>
/// 简单图形类——圆
/// </summary>
public class Circle : Graphics
{
    public Circle(string name)
        : base(name)
    { }

    // 重写父类抽象方法
    public override void Draw()
    {
        Console.WriteLine("画  " + Name);
    }
}

/// <summary>
/// 复杂图形,由一些简单图形组成,这里假设该复杂图形由一个圆两条线组成的复杂图形
/// </summary>
public class ComplexGraphics : Graphics
{
    private List<Graphics> complexGraphicsList = new List<Graphics>();
    public ComplexGraphics(string name)
        : base(name)
    { }

    /// <summary>
    /// 复杂图形的画法
    /// </summary>
    public override void Draw()
    {
        foreach (Graphics g in complexGraphicsList)
        {
            g.Draw();
        }
    }

    public void Add(Graphics g)
    {
        complexGraphicsList.Add(g);
    }
    public void Remove(Graphics g)
    {
        complexGraphicsList.Remove(g);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值