• C#设计模式——组合模式


    一、组合模式介绍:

    组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以向处理简单元素一样来处理复杂元素。允许你将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象以及对象的组合。组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。

    二、设计背景:

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

    三、相关代码:

    1、创建文件抽象类

        /// <summary>
        /// 文件抽象类
        /// </summary>
        public abstract class File
        {
            public string Name { get; set; }
            public File(string name)
            {
                this.Name = name;
            }
            public abstract void New();
            public abstract void AddFile(File file);
            public abstract void DeleteFile(File file);
        }

    2、创建具体简单对象类(简单对象):Word文档类和Excel文档类

        /// <summary>
        /// 具体简单对象类——Word文档文件
        /// </summary>
        public class Word : File
        {
            public Word(string name) : base(name)
            {
            }
    
            public override void New()
            {
                Console.WriteLine("新建Word文档:" + Name);
            }
    
            //因为文件是目录的最小单位,文件下无法创建文件,所以简单对象Word文档文件类里面的AddFolder和RemoveFolder方法没有意义
            public override void AddFile(File file)
            {
                throw new Exception("不能向Word文件创建文件");
            }
    
            public override void DeleteFile(File file)
            {
                throw new Exception("不能向Word文件删除文件");
            }
        }
        /// <summary>
        /// 具体简单对象类——Excel文档文件
        /// </summary>
        public class Excel : File
        {
            public Excel(string name) : base(name)
            {
            }
    
            public override void New()
            {
                Console.WriteLine("新建Excel文档:" + Name);
            }
    
            public override void AddFile(File file)
            {
                throw new Exception("不能向Excel文件创建文件");
            }
    
            public override void DeleteFile(File file)
            {
                throw new Exception("不能向Excel文件删除文件");
            }
        }

    3、创建文件夹类(复合对象):

        /// <summary>
        /// 文件夹类,由一些文件组成
        /// </summary>
        public class Folder : File
        {
            private List<File> file_list = new List<File>();
            public Folder(string name) : base(name)
            {
            }
    
            /// <summary>
            /// 文件夹创建各种文件
            /// </summary>
            public override void New()
            {
                foreach (var item in file_list)
                {
                    item.New();
                }
            }
    
            public override void AddFile(File file)
            {
                file_list.Add(file);
            }
            
            public override void DeleteFile(File file)
            {
                file_list.Remove(file);
            }
        }

    4、调用

            static void Main(string[] args)
            {
                Folder folder = new Folder("一个文件夹和一个Word文档组成的文件夹");
                folder.AddFile(new Word("我是Word文档1"));
    
                Folder folder2 = new Folder("一个Word文档和一个Excel文档组成的文件夹");
                folder2.AddFile(new Word("我是Word文档2"));
                folder2.AddFile(new Excel("我是Excel文档1"));
                folder.AddFile(folder2);
                Excel excel = new Excel("我是Excel文档2");
                folder.AddFile(excel);
    
                //查看文件夹
                folder.New();
                Console.ReadKey();
    
                //移除一个文件再查看文件夹
                folder.DeleteFile(excel);
                folder.New();
                Console.ReadKey();
            }

    上面的实现方式称为透明式的组合模式,由于基本文件对象不存在AddFile和DeleteFile方法,上面实现中直接通过抛出一个异常的方式来解决这样的问题的,但是我们想以一种更安全的方式来解决——因为基本文件根本不存在这样的方法,我们是不是可以移除这些方法呢?为了移除这些方法,我们就不得不修改File接口,我们把管理子对象的方法声明放在文件夹对象里面,这样简单对象Word、Excel使用这些方法时在编译时就会出错,这样的一种实现方式我们称为安全式的组合模式。具体代码如下:

        /// <summary>
        /// 文件夹类,由一些文件组成
        /// </summary>
        public class Folder : File
        {
            private List<File> file_list = new List<File>();
            public Folder(string name) : base(name)
            {
            }
    
            /// <summary>
            /// 文件夹创建各种文件
            /// </summary>
            public override void New()
            {
                foreach (var item in file_list)
                {
                    item.New();
                }
            }
    
            public void AddFile(File file)
            {
                file_list.Add(file);
            }
            
            public void DeleteFile(File file)
            {
                file_list.Remove(file);
            }
        }

    四、组合模式的三个角色:

    • 抽象构件(Component)角色:这是一个抽象角色,上面实现中File充当这个角色,在透明式的组合模式里,它给参加组合的对象定义出了公共的接口及默认行为,可以用来管理所有的子对象。在安全式的组合模式里,构件角色并不定义出管理子对象的方法,这一定义由树枝结构对象给出。
    • 树叶构件(Leaf)角色:树叶对象时没有下级子对象的对象,上面实现中Word和Excel充当这个角色,定义出参加组合的原始对象的行为
    • 树枝构件(Composite)角色:代表参加组合的有下级子对象的对象,上面实现中Folder充当这个角色,树枝对象给出所有管理子对象的方法实现,如AddFile、DeleteFile等。

    五、使用场景:

    1. 需要表示一个对象整体或部分的层次结构。
    2. 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

    六、总结:

    优点:

    1. 组合模式使得客户端代码可以一致地处理对象和对象容器,无需关系处理的单个对象,还是组合的对象容器。
    2. 将”客户代码与复杂的对象容器结构“解耦。
    3. 可以更容易地往组合对象中加入新的构件。

    缺点:

    1. 使得设计更加复杂。客户端需要花更多时间理清类之间的层次关系。
  • 相关阅读:
    forms组件、cookie与session
    choices参数、MTV与MVC模型、Ajax、序列化组件、sweetalert搭建页面、自定义分页器
    Django 常用字段,数据库查询优化 only与defer
    django配置代码
    django 模板层、模型层
    Django 请求生命周期、路由层
    centos6.8安装httpd后无法访问
    初次认识dedecms和帝国cms内容管理系统
    遇到一个json解码失败的问题
    关于apache配置映射端口
  • 原文地址:https://www.cnblogs.com/jiechou/p/9127507.html
Copyright © 2020-2023  润新知