欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 文化 > C# 设计模式之组合模式

C# 设计模式之组合模式

2024/10/24 13:25:14 来源:https://blog.csdn.net/qq_39847278/article/details/140902020  浏览:    关键词:C# 设计模式之组合模式

总目录


前言

日常使用电脑过程中,经常接触到文件夹和文件,我们知道在文件系统中,文件夹可以包含文件夹,且可以嵌套多层,最里面包含的是文件。文件作为最底层对象,里面是不可以再包含文件夹和文件的。类似于文件目录这样的结构,可以称之为树形结构。而树形结构中的对象可以分为两类,一类是:容器对象(复合对象),可以包含其他的子对象;另一类是:叶子对象(简单对象),这类对象是不能在包含其他对象的对象。由于简单对象和复合对象在功能上区别,导致在操作过程中必须区分简单对象和复合对象,这样就会导致客户调用带来不必要的麻烦,作为客户,它们希望能够始终一致地对待简单对象和复合对象。对于这样的问题,让我们看看组合模式是怎样解决这个问题的呢?


1 基础介绍

  1. 组合模式允许你将对象组合成树形结构来表现”部分-整体“的层次结构,使得客户以一致的方式处理单个对象和组合对象

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

  3. 组合模式中的角色:

    • 抽象构件角色(Component):它可以是接口或抽象类,为节点组件和容器组件对象声明接口,在该类中包含共有行为的声明。在抽象组件类中,定义了访问和管理它的子组件的方法(在透明式组合模式中是这样)。在安全式的组合模式中,构件角色并不定义出管理子对象的方法,这一定义由树枝结构对象给出。
    • 树叶构件角色(Leaf):节点对象为最小组件(可以理解为树叶),并继承自抽象构件类,实现其共有声明和方法。
    • 树枝构件角色或称容器构件类(Composite):容器对象可以包含无数节点对象和无数容器组件(可以理解为树枝,可以有无数树叶或者分支),容器对象需要实现管理子对象的方法,如Add、Remove等。

2 使用场景

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

3 实现方式

组合模式有两种实现方式:

  • 透明式的组合模式
  • 安全式的组合模式。

何为“透明式”,何为“安全式”?

透明式是指“抽象构件角色”定义的接口行为集合包含两个部分,一部分是叶子对象本身所包含的行为(比如Operation),另外一部分是容器对象本身所包含的管理子对象的行为(Add,Remove)。这个抽象构件必须同时包含这两类对象所有的行为,客户端代码才会透明的使用,无论调用容器对象还是叶子对象,接口方法都是一样的,这就是透明,针对客户端代码的透明,但是也有他自己的问题,叶子对象不会包含自己的子对象,为什么要有Add,Remove等类似方法呢,调用叶子对象这样的方法可能(注意:我这里说的是可能,因为有些人会把这些方法实现为空,不做任何动作,当然也不会有异常抛出了,不要抬杠)会抛出异常,这样就不安全了,然后人们就提出了“安全式的组合模式”。所谓安全式是指“抽象构件角色”只定义叶子对象的方法,确切的说这个抽象构件只定义两类对象共有的行为,然后容器对象的方法定义在“树枝构件角色”上,这样叶子对象有叶子对象的方法,容器对象有容器对象的方法,这样责任很明确,当然调用肯定不会抛出异常了。

1. 透明式的组合模式

现在我们分析,在文件系统中存在的文件夹和文件 两个对象,常用的操作无非就是
1 添加文件夹或文件
2 移除文件夹或文件
3 打开文件夹或文件
那么我们对外提供的就是这三个接口,这就是容器对象(复合对象)和叶子对象(简单对象)统一的操作接口。

定义抽象类,规范对外提供的接口,这里就是定义文件系统的抽象类

    //文件系统的抽象类//负责定义容器对象和简单对象统一对象提供的接口public abstract class AbstractFolder {// 添加文件夹或文件public abstract void Add(AbstractFolder folder);//删除文件夹或文件public abstract void Remove(AbstractFolder folder);//打开文件夹或文件public abstract void Open();}

定义叶子对象,实现抽象类的接口,这是就是文件

    public class File : AbstractFolder{//由于文件是叶子对象,是无法再向文件内添加/移除 文件夹或文件的,因此此处通过抛异常处理public override void Add(AbstractFolder folder){throw new Exception("无法向文件中添加文件夹或文件");}public override void Remove(AbstractFolder folder){throw new Exception("无法向文件中移除文件夹或文件");}public override void Open(){Console.WriteLine("打开文件!");}}

定义容器对象,同样实现文件抽象类的接口,这里就是文件夹

    public class Folder : AbstractFolder{public override void Add(AbstractFolder folder){Console.WriteLine("添加文件夹或者文件");}public override void Open(){Console.WriteLine("打开文件价!");}public override void Remove(AbstractFolder folder){Console.WriteLine("移除文件夹或者文件");}}

客户端调用:

        static void Main(string[] args){AbstractFolder file = new File();file.Open();//file.Add(new Folder());//会抛异常//file.Remove(new Folder());//会抛异常AbstractFolder folder = new Folder();folder.Open();folder.Remove(new Folder());folder.Add(new Folder());}

我们发现:文件其实是不需要 Add与Remove 方法的,但是为了保持文件和文件夹一致,对外提供一致的接口,因此文件就一同继承Add与Remove方法,并在方法中做出抛异常的处理。优点是让我们清晰透明的知道其中的实现过程,缺点就是对于客户端的调用并不安全,正因如此就有了安全式的组合模式。

2. 安全式的组合模式

1 定义文件抽象类

	//文件抽象类中不再定义Add和Remove方法//而是只定义,文件夹和文件都有的接口Openpublic abstract class AbstractFolder {//打开文件夹或文件public abstract void Open();}// 文件类,也只需实现一个Open方法即可public class File : AbstractFolder{public override void Open(){Console.WriteLine("打开文件!");}}//将文件夹特有的操作,定义在文件夹实现类中public class Folder : AbstractFolder{public void Add(AbstractFolder folder){Console.WriteLine("添加文件夹或者文件");}public override void Open(){Console.WriteLine("打开文件价!");}public void Remove(AbstractFolder folder){Console.WriteLine("移除文件夹或者文件");}}

客户端调用:

        static void Main(string[] args){AbstractFolder file = new File();file.Open();Folder folder = new Folder();folder.Open();folder.Remove(new Folder());folder.Add(new Folder());}

安全式 组合模式:将文件夹和文件共有的Open 行为,定义在了抽象类中,将文件夹自己需要的Add 和Remove行为定义在文件夹自己的类中!

4 优缺点分析

优点:

  • 组合模式使得客户端代码可以一致地处理单个对象和组合对象
  • 将”客户代码与复杂的对象容器结构“解耦。
  • 可以更容易地往组合对象中加入新的构件。

缺点:

  • 使得设计更加复杂。客户端需要花更多时间理清类之间的层次关系。(这个是几乎所有设计模式所面临的问题)。

结语

希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
C#设计模式(10)——组合模式(Composite Pattern)
C#设计模式之九组合模式(Composite Pattern)【结构型】
c#中组合模式详解

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com