【23种设计模式】组合模式(七)

前言

组合模式 ,英文名称是:Composite Pattern。当我们谈到这个模式的时候,有一个物件和这个模式很像,也符合这个模式要表达的意思,那就是"俄罗斯套娃"。"俄罗斯套娃"就是大的瓷器娃娃里面装着一个小的瓷器娃娃,小的瓷器娃娃里面再装着更小的瓷器娃娃,直到最后一个不能再装更小的瓷器娃娃的那个瓷器娃娃为止。在我们的操作系统中有文件夹的概念,文件夹可以包含文件夹,可以嵌套多层,最里面包含的是文件,这个概念和"俄罗斯套娃"很像。

组合模式的定义

客户代码过多地依赖于对象容器复杂的内部实现结构,对象容器内部实现结构的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等方面的弊端。组合设计模式就是将对象组合成树形结构以表示"部分-整体"的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。

组合模式的组成

  • 抽象构件角色(Component):这是个抽象角色,它给参加组合的对象定义出了公共的接口及默认行为,可以用来管理所有的子对象。在安全式的组合模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝结构对象给出。

  • 树叶构件角色(Leaf):树叶对象是没有下级子对象的对象,定义出参加组合的原始对象的行为。(原始对象的行为可以理解为没有容器对象管理子对象的方法,或者 【原始对象行为】+【管理子对象的行为(Add,Remove等)】=面对客户代码的接口行为集合)

  • 树枝构件角色(Composite):代表参加组合的有下级子对象的对象,树枝对象给出所有管理子对象的方法实现,如Add、Remove等。

组合模式的代码实现

组合模式有两种实现方式,一种是:透明式的组合模式,另外一种是:安全式的组合模式。

所谓透明式是指"抽象构件角色"定义的接口行为集合包含两个部分,一部分是叶子对象本身所包含的行为(比如Operation),另外一部分是容器对象本身所包含的管理子对象的行为(Add,Remove)。这个抽象构件必须同时包含这两类对象所有的行为,客户端代码才会透明的使用,无论调用容器对象还是叶子对象,接口方法都是一样的,这就是透明

所谓安全式是指**"抽象构件角色"只定义叶子对象的方法,确切的说这个抽象构件只定义两类对象共有的行为,然后容器对象的方法定义在"树枝构件角色"上,这样叶子对象有叶子对象的方法,容器对象有容器对象的方法,这样责任很明确,当然调用肯定不会抛出异常了。**

大家可以根据自己的情况自行选择是实现为"透明式"还是"安全式"的,以下我们会针对这两种情况都有实现,具体实现如下:

透明式

代码定义

C# 复制代码
 /// <summary>
    /// Transparent 透明式实现
    /// </summary>
    public class Transparent
    {
        /// <summary>
        /// 该抽象类就是文件夹抽象接口的定义,该类型就相当于是抽象构件Component类型
        /// </summary>
        public abstract class Folder
        {
            //增加文件夹或文件
            public abstract void Add(Folder folder);

            //删除文件夹或者文件
            public abstract void Remove(Folder folder);

            //打开文件或者文件夹--该操作相当于Component类型的Operation方法
            public abstract void Open();
        }

        /// <summary>
        /// 该Word文档类就是叶子构件的定义,该类型就相当于是Leaf类型,不能在包含子对象
        /// </summary>
        public sealed class Word : Folder
        {
            //增加文件夹或文件
            public override void Add(Folder folder)
            {
                throw new Exception("Word文档不具有该功能");
            }

            //删除文件夹或者文件
            public override void Remove(Folder folder)
            {
                throw new Exception("Word文档不具有该功能");
            }

            //打开文件--该操作相当于Component类型的Operation方法
            public override void Open()
            {
                Console.WriteLine("打开Word文档,开始进行编辑");
            }
        }

        /// <summary>
        /// SonFolder类型就是树枝构件,由于我们使用的是"透明式",所以Add,Remove都是从Folder类型继承下来的
        /// </summary>
        public class SonFolder : Folder
        {
            //增加文件夹或文件
            public override void Add(Folder folder)
            {
                Console.WriteLine("文件或者文件夹已经增加成功");
            }

            //删除文件夹或者文件
            public override void Remove(Folder folder)
            {
                Console.WriteLine("文件或者文件夹已经删除成功");
            }

            //打开文件夹--该操作相当于Component类型的Operation方法
            public override void Open()
            {
                Console.WriteLine("已经打开当前文件夹");
            }
        }
    }

调用实现

C# 复制代码
  public void RunTest()
        {
            //Folder myword = new Word();
            //myword.Open();//打开文件,处理文件

            //myword.Add(new SonFolder());//抛出异常
            //myword.Remove(new SonFolder());//抛出异常


            Folder myfolder = new SonFolder();
            myfolder.Open();//打开文件夹

            myfolder.Add(new SonFolder());//成功增加文件或者文件夹
            myfolder.Remove(new SonFolder());//成功删除文件或者文件夹

            Console.Read();
        }
安全式

代码定义

C# 复制代码
  /// <summary>
    /// Secure 安全式实现
    /// </summary>
    public class Secure
    {
        /// <summary>
        /// 该抽象类就是文件夹抽象接口的定义,该类型就相当于是抽象构件Component类型
        /// </summary>
        public abstract class Folder //该类型少了容器对象管理子对象的方法的定义,换了地方,在树枝构件也就是SonFolder类型
        {
            //打开文件或者文件夹--该操作相当于Component类型的Operation方法
            public abstract void Open();
        }

        /// <summary>
        /// 该Word文档类就是叶子构件的定义,该类型就相当于是Leaf类型,不能在包含子对象
        /// </summary>
        public sealed class Word : Folder  //这类型现在很干净
        {
            //打开文件---该操作相当于Component类型的Operation方法
            public override void Open()
            {
                Console.WriteLine("打开Word文档,开始进行编辑");
            }
        }

        /// <summary>
        /// SonFolder类型就是树枝构件,现在由于我们使用的是"安全式",所以Add,Remove都是从此处开始定义的
        /// </summary>
        public abstract class SonFolder : Folder //这里可以是抽象接口,可以自己根据自己的情况而定
        {
            //增加文件夹或文件
            public abstract void Add(Folder folder);

            //删除文件夹或者文件
            public abstract void Remove(Folder folder);

            //打开文件夹--该操作相当于Component类型的Operation方法
            public override void Open()
            {
                Console.WriteLine("已经打开当前文件夹");
            }
        }

        /// <summary>
        /// NextFolder类型就是树枝构件的实现类
        /// </summary>
        public sealed class NextFolder : SonFolder
        {
            //增加文件夹或文件
            public override void Add(Folder folder)
            {
                Console.WriteLine("文件或者文件夹已经增加成功");
            }

            //删除文件夹或者文件
            public override void Remove(Folder folder)
            {
                Console.WriteLine("文件或者文件夹已经删除成功");
            }

            //打开文件夹--该操作相当于Component类型的Operation方法
            public override void Open()
            {
                Console.WriteLine("已经打开当前文件夹");
            }
        }

    }

调用实现

C# 复制代码
  public void RunTest()
        {
            //这是安全的组合模式
            Folder myword = new Word();

            myword.Open();//打开文件,处理文件


            Folder myfolder = new NextFolder();
            myfolder.Open();//打开文件夹

            //此处要是用增加和删除功能,需要转型的操作,否则不能使用
            ((SonFolder)myfolder).Add(new NextFolder());//成功增加文件或者文件夹
            ((SonFolder)myfolder).Remove(new NextFolder());//成功删除文件或者文件夹

        }

组合模式的优缺点

优点
  • 组合模式使得客户端代码可以一致地处理对象和对象容器,无需关心处理的是单个对象,还是组合的对象容器。

  • 将"客户代码与复杂的对象容器结构"解耦。

  • 可以更容易地往组合对象中加入新的构件。

缺点
  • 使得设计更加复杂。客户端需要花更多时间理清类之间的层次关系。
相关推荐
波波0076 小时前
每日一题:中间件是如何工作的?
中间件·.net·面试题
无风听海7 小时前
.NET 10之可空引用类型
数据结构·.net
码云数智-园园7 小时前
基于 JSON 配置的 .NET 桌面应用自动更新实现指南
.net
无风听海7 小时前
.NET 10 之dotnet run的功能
.net
岩屿7 小时前
Ubuntu下安装Docker并部署.NET API(二)
运维·docker·容器·.net
码云数智-大飞7 小时前
.NET 中高效实现 List 集合去重的多种方法详解
.net
easyboot7 小时前
使用tinyply.net保存ply格式点云
.net
张人玉7 小时前
WPF 多语言实现完整笔记(.NET 4.7.2)
笔记·.net·wpf·多语言实现·多语言适配
波波0071 天前
Native AOT 能改变什么?.NET 预编译技术深度剖析
开发语言·.net
Crazy Struggle2 天前
.NET 中如何快速实现 List 集合去重?
c#·.net