结构型模式 - 组合模式Composite Pattern

学习而来,代码是自己敲的。也有些自己的理解在里边,有问题希望大家指出。

 

组合模式的定义与特点

        组合(Composite Pattern)模式的定义:有时又叫作整体-部分(Part-Whole)模式,它是一种将对象组合成树状的层次结构的模式,用来表示“整体-部分”的关系,使用户对单个对象和组合对象具有一致的访问性,属于结构型设计模式。  

        组合模式一般用来描述整体与部分的关系,它将对象组织到树形结构中,顶层的节点被称为根节点,根节点下面可以包含树枝节点和叶子节点,树枝节点下面又可以包含树枝节点和叶子节点,树形结构图如下。  

组合模式示意图

         由上图可以看出,其实根节点和树枝节点本质上属于同一种数据类型,可以作为容器使用;而叶子节点与树枝节点在语义上不属于用一种类型。但是在组合模式中,会把树枝节点和叶子节点看作属于同一种数据类型(用统一接口定义),让它们具备一致行为。  

        这样,在组合模式中,整个树形结构中的对象都属于同一种类型,带来的好处就是用户不需要辨别是树枝节点还是叶子节点,可以直接进行操作,给用户的使用带来极大的便利。  

组合模式的主要优点有:

  • 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码;
  • 更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;

其主要缺点是:

  • 设计较复杂,客户端需要花更多时间理清类之间的层次关系;
  • 不容易限制容器中的构件;
  • 不容易用继承的方法来增加构件的新功能;

组合模式的结构与实现

组合模式的结构不是很复杂,下面对它的结构和实现进行分析。

1. 模式的结构

组合模式包含以下主要角色。

  1. 抽象构件(Component)角色:它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。(总的抽象类或接口,定义一些通用的方法,比如新增、删除)
  2. 树叶构件(Leaf)角色:是组合中的叶节点对象,它没有子节点,用于继承或实现抽象构件。
  3. 树枝构件(Composite)角色 / 中间构件:是组合中的分支节点对象,它有子节点,用于继承和实现抽象构件。它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

组合模式分为透明式的组合模式和安全式的组合模式。  

(1) 透明方式

        在该方式中,由于抽象构件声明了所有子类中的全部方法,所以客户端无须区别树叶对象和树枝对象,对客户端来说是透明的。但其缺点是:树叶构件本来没有 Add()、Remove() 及 GetChild() 方法,却要实现它们(空实现或抛异常),这样会带来一些安全性问题。其结构图如图 1 所示。  

图1  透明式的组合模式的结构图

 

(2) 安全方式

        在该方式中,将管理子构件的方法移到树枝构件中,抽象构件和树叶构件没有对子对象的管理方法,这样就避免了上一种方式的安全性问题,但由于叶子和分支有不同的接口,客户端在调用时要知道树叶对象和树枝对象的存在,所以失去了透明性。其结构图如图 2 所示。  

图2    安全式的组合模式的结构图​​​​

2. 模式的实现

假如要访问集合 c0={leaf1,{leaf2,leaf3}} 中的元素,其对应的树状图如图 3 所示。

 

案例

  代码样例

using DesignPattern.CompositePattern;
using System;

namespace DesignPattern
{
    internal class Program
    {
        static void Main(string[] args)
        {
            CompositeHelper();
        }

        #region Pattern - Composite
        static void CompositeHelper()
        {
            Composite _root = new TreeLimb("小三门目录");

            Composite art = new TreeLimb("美术");
            Composite sports = new TreeLimb("体育");
            Composite music = new TreeLimb("音乐");
            _root.Add(art);
            _root.Add(sports);
            _root.Add(music);

            Composite painting = new TreeLimb("油画类");
            art.Add(painting);

            Composite running = new TreeLimb("跑步类");
            Composite swimming = new TreeLimb("游泳类");
            sports.Add(running);
            sports.Add(swimming);

            Composite soprano = new TreeLimb("高音类");
            Composite opera = new TreeLimb("戏曲类");
            Composite bass = new TreeLimb("低音类");
            music.Add(soprano);
            music.Add(opera);
            music.Add(bass);

            Composite painting1 = new Leaf("油画精选1");
            Composite painting2 = new Leaf("油画精选2");
            painting.Add(painting1);
            painting.Add(painting2);

            Composite opera1 = new TreeLimb("戏曲选集1");
            Composite opera2 = new TreeLimb("戏曲选集2");
            Composite opera3 = new TreeLimb("戏曲选集3");
            opera.Add(opera1);
            opera.Add(opera2);
            opera.Add(opera3);
            opera.Remove(opera2);

            Composite swimming1 = new Leaf("花样游泳");
            Composite swimming2 = new Leaf("200m游泳");
            Composite swimming3 = new Leaf("800m接力游泳");
            Composite swimming4 = new Leaf("1600m接力游泳");
            swimming.Add(swimming1);
            swimming.Add(swimming2);
            swimming.Add(swimming3);
            swimming.Add(swimming4);

            _root.Depth(0);
            Console.WriteLine();
            Console.WriteLine("文章数:" + _root.ShowCount());

            Console.ReadLine();
        }
        #endregion
    }
}

//======================================================================================
using System;
using System.Collections.Generic;
namespace DesignPattern.CompositePattern
{
    /// <summary>
    /// 抽象合成类
    /// </summary>
    public abstract class Composite
    {
        /// <summary>
        /// 组件名
        /// </summary>
        public string Name;
        public Composite(string name)
        {
            Name = name;
        }

        /// <summary>
        /// 增加子节点
        /// </summary>
        public abstract void Add(Composite composite);

        /// <summary>
        /// 删除子节点
        /// </summary>
        public abstract void Remove(Composite composite);

        /// <summary>
        /// 返回最终子节点数量
        /// </summary>
        public abstract int ShowCount();

        /// <summary>
        /// 节点展示深度
        /// </summary>
        /// <param name="depth"> - 的数量</param>
        public abstract void Depth(int depth);
    }

    /// <summary>
    /// 枝干节点
    /// </summary>
    public class TreeLimb : Composite
    {
        private List<Composite> m_Composite = new List<Composite>();

        public TreeLimb(string name) : base(name)
        {
            Name = name;
        }
        public override void Add(Composite component)
        {
            m_Composite.Add(component);
        }

        public override void Depth(int depth)
        {
            Console.WriteLine(new string('-', depth * 2) + Name);
            foreach (Composite item in m_Composite)
            {
                item.Depth(depth + 1);
            }
        }

        public override void Remove(Composite component)
        {
            m_Composite.Remove(component);
        }

        public override int ShowCount()
        {
            int count = 0;
            foreach (var item in m_Composite)
            {
                count += item.ShowCount();
            }
            return count;
        }
    }

    /// <summary>
    /// 子节点
    /// </summary>
    public class Leaf : Composite
    {
        public Leaf(string name) : base(name)
        {
            Name = name;
        }
        public override void Add(Composite composite)
        {
            throw new InvalidOperationException("叶子节点不能添加元素");
        }

        public override void Depth(int depth)
        {
            Console.WriteLine(new string('-', depth * 2) + Name);
        }

        public override void Remove(Composite composite)
        {
            throw new InvalidOperationException("叶子节点不能删除元素");
        }

        public override int ShowCount()
        {
            return 1;
        }
    }
}

运行结果:


 

 

希望大家:点赞,留言,关注咯~    
😘😘😘😘

唠家常

        今日分享结束啦,小伙伴们你们get到了么,你们有没有更好的办法呢,可以评论区留言分享,也可以加QQ:841298494,大家一起进步。

  • 客官,看完get之后记得点赞哟!
  • 小伙伴你还想要别的知识?好的呀,分享给你们😄

今日推荐

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青衫磊落长歌行

觉得小黑这篇文章不赖,打赏哟~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值