c#组合模式详解

这篇具有很好参考价值的文章主要介绍了c#组合模式详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

基础介绍:

  组合模式用于表示部分-整体层次结构。适用于希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象的情况。

  顾名思义,什么叫部分-整体,比如常见的前端UI,一个DIV标签中可以存在多个A标签、P标签、DIV标签等等。

  相较于DIV这个容器整体而言,其中所含的A标签、P标签甚至是DIV标签都是单个的部分。

  而显示的时候却是一视同仁,不分部分还是整体。

  这就是典型的组合模式。

  再比如WinForms应用程序中,Label、TextBox等这样简单的控件,可以理解为节点对象,它们中无法再插入其他控件,它们就是最小的。

  而比如GroupBox、DataGrid这样由多个简单控件组成的复合控件或者容器,就可以理解为容器对象,它们中可以再插入其他的节点对象,甚至是再插入其他容器对象。

  但不管是Label这种节点对象还是DataGrid这种容器对象,想要显示的话都需要执行OnPaint方法。

  为了表示这种对象之间整体与部分的层次结构,System.Windows.Forms.Control类就是应用了这种组合模式。

  这样就可以简单的把组合模式分为三个部分:

  • 抽象组件类(Component):它可以是接口或抽象类,为节点组件和容器组件对象声明接口,在该类中包含共有行为的声明。在抽象组件类中,定义了访问及管理它的子组件的方法。
  • 节点组件类(Leaf):节点对象为最小组件(可以理解为树叶),并继承自抽象组件类,实现其共有声明和方法。
  • 容器组件类(Composite):容器对象可以包含无数节点对象和无数容器组件(可以理解为树枝,可以有无数树叶或者分支),容器对象需要实现管理子对象的方法,如Add、Remove等。

应用场景:

  当发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑使用组合模式了

  UI的一系列控件就是使用了组合模式,整体和部分可以被一致对待。

  组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

  以下情况下适用Composite模式:

  1.对象的部分-整体层次结构。

  2.忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象。

创建方式:

 组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进行一致处理的原因。

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

 

  透明方式————————————————

  Leaf叶类中也有Add 与 Remove方法,这种方式叫透明方式。

  也就是说在Component中声明所有用来管理子对象的方法,其中包括Add、Remove等。

  这样实现Component接口的所有子类都具备了Add与Remove。

  这样做的好处是叶节点和枝节点对于外界没有区别,它们具有一致的行为接口。

  但问题也很明显,因为Leaf类本身不具备Add、Remove方法的功能,其实现是没有意义的。

 

  安全方式————————————————

  在Component接口中不去声明Add与Remove方法,那么子类Leaf也就不用必须实现它们,而在Composite类中声明所有用来管理子类对象的方法。
  
  

  以文档管理器为例,文件夹为Composite,各类文档为Leaf

  1. 透明方式

     1.抽象类

     1     /// <summary>
     2     /// 抽象组件类(Component)
     3     /// </summary>
     4     public abstract class DocumentComponent
     5     {
     6         public string Name { get; set; }
     7         protected List<DocumentComponent> mChildren;
     8         public List<DocumentComponent> Children
     9         {
    10             get { return mChildren; }
    11         }
    12         public DocumentComponent(string name)
    13         {
    14             this.Name = name;
    15             mChildren = new List<DocumentComponent>();
    16         }
    17 
    18         
    19         public abstract void AddChild(DocumentComponent document);
    20 
    21         public abstract void RemoveChild(DocumentComponent document);
    22 
    23         public abstract void Show();
    24     }

    接口或抽象类,为节点组件和容器组件对象声明接口,在该类中包含共有行为的声明。

    在抽象组件类中,定义了访问及管理它的子组件的方法。

    本实例中Show为节点和容器组件共有方法,AddChildRemoveChild为容器组件方法。

    本类主要是为了让节点类和容器类进行继承方便统一管理

    2.节点组件类

     1     /// <summary>
     2     /// 节点组件类(Leaf),各类文档,每类型可以添加一个对应类。
     3     /// </summary>
     4     public sealed class Word : DocumentComponent
     5     {
     6         public Word(string name)
     7             : base(name)
     8         { }
     9         public override void AddChild(DocumentComponent document)
    10         {
    11             throw new Exception("节点类不支持");
    12         }
    13 
    14         public override void RemoveChild(DocumentComponent document)
    15         {
    16             throw new Exception("节点类不支持");
    17         }
    18 
    19         public override void Show()
    20         {
    21             Console.WriteLine("这是一篇word文档:" + Name);
    22         }
    23     }

    节点对象为最小组件(可以理解为树叶),并继承自抽象组件类,实现show方法。

    AddChildRemoveChild为容器组件方法,在节点类中抛出异常即可。

    该类是最小单位,没有子节点。

    本类一个word文档对象,如果有多个类型的文档,可以声明多个类。

    3.容器组件类

     1     /// <summary>
     2     /// 容器组件类(Composite),文件夹
     3     /// </summary>
     4     public class Folder : DocumentComponent
     5     {
     6         public Folder(string name)
     7             : base(name)
     8         { }
     9         public override void AddChild(DocumentComponent document)
    10         {
    11             mChildren.Add(document);
    12             Console.WriteLine("文档或文件夹增加成功");
    13         }
    14         public override void RemoveChild(DocumentComponent document)
    15         {
    16             mChildren.Remove(document);
    17             Console.WriteLine("文档或文件夹删除成功");
    18         }
    19         public override void Show()
    20         {
    21             Console.WriteLine("这是一个文件夹:" + Name);
    22         }
    23     }

    容器对象可以包含无数节点对象和无数容器组件(可以理解为树枝,可以有无数树叶或者分支),容器对象需要实现管理子对象的方法,如AddChildRemoveChild等。

    本类是一个文件夹对象。

    4.客户端

     1     /// <summary>
     2     /// 客户端
     3     /// </summary>
     4     class Client
     5     {
     6         /// <summary>
     7         /// 广度优先检索
     8         /// </summary>
     9         /// <param name="component"></param>
    10         private static void BreadthFirstSearch(DocumentComponent component)
    11         {
    12             Queue<DocumentComponent> q = new Queue<DocumentComponent>();
    13             q.Enqueue(component);
    14             Console.WriteLine(component.Name);
    15             while (q.Count > 0)
    16             {
    17                 DocumentComponent temp = q.Dequeue();
    18                 List<DocumentComponent> children = temp.Children;
    19                 foreach (DocumentComponent child in children)
    20                 {
    21                     Console.WriteLine(child.Name);
    22                     q.Enqueue(child);
    23                 }
    24             }
    25         }
    26 
    27         /// <summary>
    28         /// 深度优先检索
    29         /// </summary>
    30         /// <param name="component"></param>
    31         private static void DepthFirstSearch(DocumentComponent component)
    32         {
    33             Console.WriteLine(component.Name);
    34             List<DocumentComponent> children = component.Children;
    35             if (children == null || children.Count == 0) return;
    36             foreach (DocumentComponent child in children)
    37             {
    38                 DepthFirstSearch(child);
    39             }
    40         }
    41 
    42         static void Main(string[] args)
    43         {
    44             Console.WriteLine("创建三个目录:");
    45             Folder folder = new Folder("根目录");
    46             Folder folder1 = new Folder("子目录1");
    47             Folder folder2 = new Folder("子目录2");
    48 
    49             Console.WriteLine("\r\n创建两个文档:");
    50             Word word1 = new Word("word文档1");
    51             Word word2 = new Word("word文档2");
    52 
    53             Console.WriteLine("\r\n将子目录1添加到根目录下:");
    54             folder.AddChild(folder1);
    55             Console.WriteLine("\r\n将子目录2添加到子目录1下:");
    56             folder1.AddChild(folder2);
    57 
    58             Console.WriteLine("\r\n将word文档1添加到子目录2下:");
    59             folder2.AddChild(word1);
    60             Console.WriteLine("\r\n将word文档2添加到根目录下:");
    61             folder.AddChild(word2);
    62 
    63             Console.WriteLine("\r\n广度优先列表:");
    64             DepthFirstSearch(folder);
    65             Console.WriteLine("\r\n深度优先列表:");
    66             BreadthFirstSearch(folder);
    67 
    68             Console.ReadKey();
    69         }
    70 
    71 
    72     }

    c#组合模式详解

    注:BreadthFirstSearch为广度优先检索,依次列出所有元素。DepthFirstSearch为深度优先检索,列举完一个文件夹后,返回根目录继续列举其他文件夹。

    通过上述实例可以看出,文件夹可以创建N个子文件夹,但文档只能放在文件夹中,无法放在另一个文档中。

  2. 安全方式

      1     /// <summary>
      2     /// 抽象组件类(Component)
      3     /// </summary>
      4     public abstract class DocumentComponent
      5     {
      6         public string Name { get; set; }
      7         protected List<DocumentComponent> mChildren;
      8         public List<DocumentComponent> Children
      9         {
     10             get { return mChildren; }
     11         }
     12         public DocumentComponent(string name)
     13         {
     14             this.Name = name;
     15             mChildren = new List<DocumentComponent>();
     16         }
     17 
     18         public abstract void Show();
     19     }
     20 
     21     /// <summary>
     22     /// 节点组件类(Leaf),各类文档,每类型可以添加一个对应类。
     23     /// </summary>
     24     public sealed class Word : DocumentComponent
     25     {
     26         public Word(string name)
     27             : base(name)
     28         { }
     29 
     30         public override void Show()
     31         {
     32             Console.WriteLine("这是一篇word文档:" + Name);
     33         }
     34     }
     35 
     36     /// <summary>
     37     /// 容器组件类(Composite),文件夹
     38     /// </summary>
     39     public class Folder : DocumentComponent
     40     {
     41         public Folder(string name)
     42             : base(name)
     43         { }
     44         public void AddChild(DocumentComponent document)
     45         {
     46             mChildren.Add(document);
     47             Console.WriteLine("文档或文件夹增加成功");
     48         }
     49         public void RemoveChild(DocumentComponent document)
     50         {
     51             mChildren.Remove(document);
     52             Console.WriteLine("文档或文件夹删除成功");
     53         }
     54         public override void Show()
     55         {
     56             Console.WriteLine("这是一个文件夹:" + Name);
     57         }
     58     }
     59 
     60 
     61     /// <summary>
     62     /// 客户端
     63     /// </summary>
     64     class Client
     65     {
     66         /// <summary>
     67         /// 广度优先检索
     68         /// </summary>
     69         /// <param name="component"></param>
     70         private static void BreadthFirstSearch(DocumentComponent component)
     71         {
     72             Queue<DocumentComponent> q = new Queue<DocumentComponent>();
     73             q.Enqueue(component);
     74             Console.WriteLine(component.Name);
     75             while (q.Count > 0)
     76             {
     77                 DocumentComponent temp = q.Dequeue();
     78                 List<DocumentComponent> children = temp.Children;
     79                 foreach (DocumentComponent child in children)
     80                 {
     81                     Console.WriteLine(child.Name);
     82                     q.Enqueue(child);
     83                 }
     84             }
     85         }
     86 
     87         /// <summary>
     88         /// 深度优先检索
     89         /// </summary>
     90         /// <param name="component"></param>
     91         private static void DepthFirstSearch(DocumentComponent component)
     92         {
     93             Console.WriteLine(component.Name);
     94             List<DocumentComponent> children = component.Children;
     95             if (children == null || children.Count == 0) return;
     96             foreach (DocumentComponent child in children)
     97             {
     98                 DepthFirstSearch(child);
     99             }
    100         }
    101 
    102         static void Main(string[] args)
    103         {
    104             Console.WriteLine("创建三个目录:");
    105             Folder folder = new Folder("根目录");
    106             Folder folder1 = new Folder("子目录1");
    107             Folder folder2 = new Folder("子目录2");
    108 
    109             Console.WriteLine("\r\n创建两个文档:");
    110             Word word1 = new Word("word文档1");
    111             Word word2 = new Word("word文档2");
    112 
    113             Console.WriteLine("\r\n将子目录1添加到根目录下:");
    114             folder.AddChild(folder1);
    115             Console.WriteLine("\r\n将子目录2添加到子目录1下:");
    116             folder1.AddChild(folder2);
    117 
    118             Console.WriteLine("\r\n将word文档1添加到子目录2下:");
    119             folder2.AddChild(word1);
    120             Console.WriteLine("\r\n将word文档2添加到根目录下:");
    121             folder.AddChild(word2);
    122 
    123             Console.WriteLine("\r\n广度优先列表:");
    124             DepthFirstSearch(folder);
    125             Console.WriteLine("\r\n深度优先列表:");
    126             BreadthFirstSearch(folder);
    127 
    128             Console.ReadKey();
    129         }
    130 
    131     }

    从上述实例中可以看出,安全模式其实就是把共有的方法放在抽象类的。

    文件夹独有的方法放在容器类中,这样做保证了节点类就没有Add和Remove等无用方法。

总结:

  组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以向处理简单元素一样来处理复杂元素。

  

  文章来源地址https://www.toymoban.com/news/detail-746127.html

到了这里,关于c#组合模式详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式详解(十一)——组合模式

    组合模式定义 组合模式(Composite Pattern)是一种结构型设计模式,又叫部分整体模式,它将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。

    2024年02月22日
    浏览(39)
  • 设计模式详解-组合模式(整体部分模式)

    类型:结构型模式 特点:依据树形结构来组合对象,用来表示部分以及整体层次 作用:模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦,使用户对单个对象和组合对象的使用具有一致性。

    2024年02月12日
    浏览(39)
  • 【设计模式——学习笔记】23种设计模式——组合模式Composite(原理讲解+应用场景介绍+案例介绍+Java代码实现)

    编写程序展示一个学校院系结构: 需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系 【传统方式】 将学院看做是学校的子类,系是学院的子类,小的组织继承大的组织 分析: 在一个页面中展示出学校的院系组成,一个学校有多个

    2024年02月15日
    浏览(45)
  • 15.一种坍缩式的简单——组合模式详解

    当曾经的孩子们慢慢步入社会才知道,那年味渐淡的春节就像是疾驰在人生路上的暂停键。 它允许你在隆隆的鞭炮声中静下心来,瞻前顾后,怅然若失。 也允许你在寂静的街道上屏气凝神,倾听自己胸腔里的那团人声鼎沸。 孩子们会明白的,就像他们步入大学校园时候渐渐

    2024年02月21日
    浏览(40)
  • c#中原型模式详解

    基础介绍:    具体可分为2个角色:     Prototype(原型类):声明一个Clone自身的接口;     ConcretePrototype(具体原型类):,实现一个Clone自身的操作。 在原型模式中,Prototype通常提供一个包含Clone方法的接口,具体的原型ConcretePrototype使用Clone方法完成对象的创

    2024年02月05日
    浏览(42)
  • c#中工厂模式详解

    总体介绍:   工厂模式主要有三种类型: 简单工厂 、 工厂方法 和 抽象工厂 ,该模式用于 封装 和 管理对象的创建 ,是一种 创建型模式 。   万物皆对象,创建对象时必然需要new该对象,当需要更改对象时,需要把项目中所有地方都修改一遍,这显然违背了软件设计

    2024年02月06日
    浏览(22)
  • c#享元模式详解

    基本介绍:   享元模式的定义: 运用 共享技术 有效地支持 大量 细粒度的 对象重复使用 。适用于大量小粒度的对象造成的运行效率和内存使用效率低下的情况。   “享元”顾名思义,“享” 共享 的意思,“元” 单元 ,最小对象,零部件的意思。   即从字面意思

    2024年02月06日
    浏览(31)
  • c#中命令模式详解

    基本介绍:    命令模式,顾名思义就是将 命令抽象化 ,然后将请求者和接收者通过命令进行绑定。   而命令的请求者只管下达命令,命令的接收者只管执行命令。   从而实现了解耦,请求者和接受者二者相对独立。   单独理解起来比较困难,咱们还是通过具体

    2024年02月05日
    浏览(35)
  • c#桥接模式详解

    基础介绍:   将 抽象部分 与它的 实现部分 分离,使它们都可以 独立地变化 。适用于不希望在抽象和实现部分之间有固定的绑定关系的情况,或者类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充的情况。   将抽象部分与实现部分分离,使它们都可以独

    2024年02月05日
    浏览(28)
  • c#装饰器模式详解

    基础介绍:    动态地给一个对象添加一些额外的职责。适用于需要扩展一个类的功能,或给一个类添加多个变化的情况。   装饰器,顾名思义就是在原有基础上添加一些功能。   大家都只知道如果想单纯的给原有类增加一些功能,可以直接继续该类生成一个子类就可

    2024年02月05日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包