zoukankan      html  css  js  c++  java
  • 通俗易懂设计模式解析——组合模式

    前言

      今天介绍的是结构型设计模式中的第四个模式,也就是组合模式(Composite Pattern)。组合模式也好理解,就拿我们电脑的文件及文件夹来说吧,这就是一个较好的组合模式的例子。一个目录下面包含文件及文件夹,文件夹下面也包含文件或文件夹。在这样一层层下来,我们可以想象。他似乎像极了那个树状图。而组合模式是依据树型结构来组合对象。用来表示部分—整体层次关系。

    组合模式介绍

    一、来由

      在我们软件系统开发中,会遇到简单对象与复杂对象一起使用的情况,就好比刚刚说的文件目录一样,可以包含文件和文件夹,文件夹下面也可以包含文件和文件夹。但是由于简单对象和复杂对象在功能使用上还是有一定的区别的,可能会造成客户端调用时较为麻烦。这时候就需要将简单对象和复杂对象统一一致对待。然而组合模式也就是解决这一麻烦的。

    二、意图

      将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

    三、案例图

     

     

    四、组合模式代码示例

      看上面案例图,可以发现组合模式一般包含以下部分:

    抽象构件角色:这是一个抽象角色,它给参加组合的对象定义了公共的接口和行为,在透明式的组合模式中,包含了对所有子对象的管理。但是在安全式的组合模式中,这里不定义管理子对象的方法,而是由树枝构件定义给出。

    树叶构件:树叶构件意味着没有下级对象,定义了参加组合对象的原始行为。

    树枝构件:代表有下级对象(树枝或树叶都有可能),给出管理其子类的对象。

     

    在组合模式中,细分为两种形式。1、透明式组合模式。2、安全式组合模式。这里我们可以看看何为透明式何为安全式:

    透明式:

      抽象构件角色定义公共的接口和行为,这里呢就包括对本对象的操作也包含其子对象的操作的。但是树叶构件对象没有其子类。但是依然继承其功能接口和行为。这里在接口和行为上,无论调用树枝构件还是树叶构件都是一样的。这就属于透明式了。

    安全式:
      由上面透明式讲的,树叶构件也会包含操作自己和子对象的接口和行为,但是没有其子对象怎么办呢?当然是可以空着不写,但会空。但是万一实现调用了呢?对吧,还是有一定的安全隐患的。那么安全式也就是说抽象构件包含操作本身对象的接口和行为,那么树叶构件也就包含操作本身对象的接口和行为了。树枝构件则实现操作自身对象的接口和行为的同时,还需要实现操作其子类的对象的接口和行为。

     

    就按开始所讲的文件目录的案例,我们通过代码一起看看,在代码中如何实现组合模式的,这样也可以更方便快捷的了解记忆:

     透明式:

    namespace Composite_Pattern
    {
        /// <summary>
        /// 透明式组合模式
        /// </summary>
        class CompositePattern
        {
        }
    
        #region 抽象构件角色——抽象文件目录============
        public abstract class Files 
        { 
            /// <summary>
            /// 增加子对象
            /// </summary>
            public abstract void Add(Files files = null, string Name = null);
            /// <summary>
            /// 删除子对象
            /// </summary>
            public abstract void Remove(Files files=null, string Name = null);
            /// <summary>
            /// 操作本身对象
            /// </summary>
            public abstract void Open(string Name);
        }
        #endregion
    
        #region 树叶构件——文件类型========================
        /// <summary>
        /// TXT文本
        /// </summary>
        public sealed class BookTxt : Files
        { 
            public override void Add(Files files=null, string Name = null)
            {
                throw new NotImplementedException("不存在添加子类操作");
            }
            public override void Remove(Files files=null, string Name = null)
            {
                throw new NotImplementedException("不存在删除子类操作");
            }
    
            public override void Open(string Name)
            {
                Console.WriteLine($"打开一个名为【{Name}】txt文本");
            }
    
            
        }
        #endregion
    
        #region 树枝构件——文件夹类型=================
        public class SubFiles : Files
        {
         
            public override void Add(Files files=null, string Name = null)
            {
                if (files != null)
                {
                    Console.WriteLine($"添加一个名为【{Name}】的文件夹");
                }
                else
                {
                    Console.WriteLine($"添加一个名为【{Name}】的txt文本");
                }
               
            }
    
            public override void Remove(Files files=null, string Name = null)
            {
                if (files != null )
                {
                    Console.WriteLine($"删除一个名为【{Name}】的文件夹");
                }
                else
                {
                    Console.WriteLine($"删除一个名为【{Name}】的txt文本");
                }
            }
    
            public override void Open(string Name)
            {
                Console.WriteLine($"打开当前名为【{Name}】文件夹文件夹");
            }
    
        }
        #endregion
    }
        class Program
        {
            static void Main(string[] args)
            {
                //操作树叶本身文件
                Files bookTxt = new BookTxt();
                bookTxt.Open("文本文件一");
    
                //新增文件夹
                Files subFiles = new SubFiles();
                subFiles.Open("文件一");
                subFiles.Add(new SubFiles(), "文件二");
    
                //删除文件
                subFiles.Remove(Name: "文本文件二");
    
                Console.ReadLine();
            }
        }

     安全式:

    namespace Composite_Pattern1
    {
        /// <summary>
        /// 安全式组合模式
        /// </summary>
        class CompositePattern
        {
        }
    
        #region 抽象构件角色——抽象文件目录============
        public abstract class Files
        { 
            /// <summary>
            /// 操作本身对象
            /// </summary>
            public abstract void Open(string Name);
        }
        #endregion
    
        #region 树叶构件——文件类型========================
        /// <summary>
        /// TXT文本
        /// </summary>
        public sealed class BookTxt : Files
        {
    
            public override void Open(string Name)
            {
                Console.WriteLine($"打开一个名为【{Name}】txt文本");
            }
    
    
        }
        #endregion
    
        #region 抽象树枝构件——安全模式,开始定义子类对象操作接口和行为=================
        public abstract  class SubFiles : Files
        {
    
            public abstract void Add(Files files = null, string Name = null);
    
            public abstract void Remove(Files files = null, string Name = null);
    
            public override void Open(string Name)
            {
                Console.WriteLine($"打开当前名为【{Name}】文件夹");
            }
    
        }
        #endregion
    
        #region 具体树枝构件——具体实现类
        public class AbSubFiles : SubFiles
        {
            public override void Add(Files files = null, string Name = null)
            {
                if (files != null)
                {
                    Console.WriteLine($"添加一个名为【{Name}】的文件夹");
                }
                else
                {
                    Console.WriteLine($"添加一个名为【{Name}】的txt文本");
                }
            }
    
            public override void Remove(Files files = null, string Name = null)
            {
                if (files != null)
                {
                    Console.WriteLine($"删除一个名为【{Name}】的文件夹");
                }
                else
                {
                    Console.WriteLine($"删除一个名为【{Name}】的txt文本");
                }
            }
            public override void Open(string Name)
            {
                Console.WriteLine($"打开当前名为【{Name}】文件夹");
            }
        }
        #endregion
    }
        class Program1
        {
            static void Main(string[] args)
            {
                //操作树叶本身文件
                BookTxt bookTxt = new BookTxt();
                bookTxt.Open("文本文件一");
    
                //新增文件夹
                AbSubFiles subFiles = new AbSubFiles();
                subFiles.Open("文件一");
                subFiles.Add(new AbSubFiles(), "文件二");
    
                //删除文件
                subFiles.Remove(Name: "文本文件二");
    
                Console.ReadLine();
    
            }
        }

    使用场景及优缺点

    一、使用场景

    1、部分——整体的环境。例如树型菜单,文件管理

    2、用户希望对简单对象与复杂对象拥有一致的操作时

    二、优点

    1、组合模式使得处理简单对象和复杂对象有一致的操作,无需关心处理的简单对象还是复杂对象

    2、更简单快捷的加入新的节点

    三、缺点

    1、使得设计复杂,难于理清层次

    2、在使用透明式的时候违背了接口分离原则,但是在使用安全式的时候又违背了依赖倒置原则

    总结

      到这里组合模式就介绍完了。这里需要提及的是在使用透明式组合模式时,树叶构件继承了操作子类的接口和行为,但是它并没有子类。在接口分离原则中提到——客户不应被强迫依赖它不使用的方法。所以这里违背了其原则,但是都遵循了依赖倒置原则,依赖于抽象。在实现安全式组合模式时,在客户端调用时依赖于具体实现,也就违背了依赖倒置原则,但是却将树叶操作与树枝构件操作分离,符合接口分离原则。在实现组合模式中不同形式实现有不同的问题。这就需要根据我们实际情况去衡量该如何使用了。

    只有经历过地狱般的折磨,才有征服天堂的力量。只有流过血的手指才能弹出世间的绝唱。

        C#设计模式系列目录

    欢迎大家扫描下方二维码,和我一起踏上设计模式的闯关之路吧!

      

  • 相关阅读:
    Unique Binary Search Trees(dp)
    Binary Tree Inorder Traversal
    Reverse Linked List II
    O​r​a​c​l​e​1​1​g​自​带​的​S​Q​L​ ​d​e​v​e​l​o​p​e​r​无​法​打​开​解​决​
    英语飙升的好方法
    MyEclipse加入jquery.js文件missing semicolon的错误
    js,jq获取手机屏幕分辨率的宽高
    给标签元素设固定宽高,内部添加滚动条显示
    解决手机端点击input的时候,页面会放大
    支付宝异步回调验证签名
  • 原文地址:https://www.cnblogs.com/hulizhong/p/11459943.html
Copyright © 2011-2022 走看看