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


    前言

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

    组合模式的定义

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

    组合模式的组成

    image

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

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

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

    组合模式的代码实现

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

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

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

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

    透明式

    代码定义

    1. ///
    2. /// Transparent 透明式实现
    3. ///
    4. public class Transparent
    5. {
    6. ///
    7. /// 该抽象类就是文件夹抽象接口的定义,该类型就相当于是抽象构件Component类型
    8. ///
    9. public abstract class Folder
    10. {
    11. //增加文件夹或文件
    12. public abstract void Add(Folder folder);
    13. //删除文件夹或者文件
    14. public abstract void Remove(Folder folder);
    15. //打开文件或者文件夹--该操作相当于Component类型的Operation方法
    16. public abstract void Open();
    17. }
    18. ///
    19. /// 该Word文档类就是叶子构件的定义,该类型就相当于是Leaf类型,不能在包含子对象
    20. ///
    21. public sealed class Word : Folder
    22. {
    23. //增加文件夹或文件
    24. public override void Add(Folder folder)
    25. {
    26. throw new Exception("Word文档不具有该功能");
    27. }
    28. //删除文件夹或者文件
    29. public override void Remove(Folder folder)
    30. {
    31. throw new Exception("Word文档不具有该功能");
    32. }
    33. //打开文件--该操作相当于Component类型的Operation方法
    34. public override void Open()
    35. {
    36. Console.WriteLine("打开Word文档,开始进行编辑");
    37. }
    38. }
    39. ///
    40. /// SonFolder类型就是树枝构件,由于我们使用的是“透明式”,所以Add,Remove都是从Folder类型继承下来的
    41. ///
    42. public class SonFolder : Folder
    43. {
    44. //增加文件夹或文件
    45. public override void Add(Folder folder)
    46. {
    47. Console.WriteLine("文件或者文件夹已经增加成功");
    48. }
    49. //删除文件夹或者文件
    50. public override void Remove(Folder folder)
    51. {
    52. Console.WriteLine("文件或者文件夹已经删除成功");
    53. }
    54. //打开文件夹--该操作相当于Component类型的Operation方法
    55. public override void Open()
    56. {
    57. Console.WriteLine("已经打开当前文件夹");
    58. }
    59. }
    60. }

    调用实现

    1. public void RunTest()
    2. {
    3. //Folder myword = new Word();
    4. //myword.Open();//打开文件,处理文件
    5. //myword.Add(new SonFolder());//抛出异常
    6. //myword.Remove(new SonFolder());//抛出异常
    7. Folder myfolder = new SonFolder();
    8. myfolder.Open();//打开文件夹
    9. myfolder.Add(new SonFolder());//成功增加文件或者文件夹
    10. myfolder.Remove(new SonFolder());//成功删除文件或者文件夹
    11. Console.Read();
    12. }

    image

    安全式

    代码定义

    1. ///
    2. /// Secure 安全式实现
    3. ///
    4. public class Secure
    5. {
    6. ///
    7. /// 该抽象类就是文件夹抽象接口的定义,该类型就相当于是抽象构件Component类型
    8. ///
    9. public abstract class Folder //该类型少了容器对象管理子对象的方法的定义,换了地方,在树枝构件也就是SonFolder类型
    10. {
    11. //打开文件或者文件夹--该操作相当于Component类型的Operation方法
    12. public abstract void Open();
    13. }
    14. ///
    15. /// 该Word文档类就是叶子构件的定义,该类型就相当于是Leaf类型,不能在包含子对象
    16. ///
    17. public sealed class Word : Folder //这类型现在很干净
    18. {
    19. //打开文件---该操作相当于Component类型的Operation方法
    20. public override void Open()
    21. {
    22. Console.WriteLine("打开Word文档,开始进行编辑");
    23. }
    24. }
    25. ///
    26. /// SonFolder类型就是树枝构件,现在由于我们使用的是“安全式”,所以Add,Remove都是从此处开始定义的
    27. ///
    28. public abstract class SonFolder : Folder //这里可以是抽象接口,可以自己根据自己的情况而定
    29. {
    30. //增加文件夹或文件
    31. public abstract void Add(Folder folder);
    32. //删除文件夹或者文件
    33. public abstract void Remove(Folder folder);
    34. //打开文件夹--该操作相当于Component类型的Operation方法
    35. public override void Open()
    36. {
    37. Console.WriteLine("已经打开当前文件夹");
    38. }
    39. }
    40. ///
    41. /// NextFolder类型就是树枝构件的实现类
    42. ///
    43. public sealed class NextFolder : SonFolder
    44. {
    45. //增加文件夹或文件
    46. public override void Add(Folder folder)
    47. {
    48. Console.WriteLine("文件或者文件夹已经增加成功");
    49. }
    50. //删除文件夹或者文件
    51. public override void Remove(Folder folder)
    52. {
    53. Console.WriteLine("文件或者文件夹已经删除成功");
    54. }
    55. //打开文件夹--该操作相当于Component类型的Operation方法
    56. public override void Open()
    57. {
    58. Console.WriteLine("已经打开当前文件夹");
    59. }
    60. }
    61. }

    调用实现

    1. public void RunTest()
    2. {
    3. //这是安全的组合模式
    4. Folder myword = new Word();
    5. myword.Open();//打开文件,处理文件
    6. Folder myfolder = new NextFolder();
    7. myfolder.Open();//打开文件夹
    8. //此处要是用增加和删除功能,需要转型的操作,否则不能使用
    9. ((SonFolder)myfolder).Add(new NextFolder());//成功增加文件或者文件夹
    10. ((SonFolder)myfolder).Remove(new NextFolder());//成功删除文件或者文件夹
    11. }

    image

    组合模式的优缺点

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

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

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

    缺点
    • 使得设计更加复杂。客户端需要花更多时间理清类之间的层次关系。
  • 相关阅读:
    RT-Thread 快速上手(学习)
    vue3.x 组件间传参
    五、Vue3基础之五
    JavaEE平台技术——预备知识(Web、Sevlet、Tomcat)
    corn表达式 具体详解与案例
    Nginx R31 doc-17-debugging 调试
    第一个ARM程序裸板点灯
    简单讲解RabbitMQ
    swagger-01-swagger介绍
    【Linux网络编程】gdb调试技巧
  • 原文地址:https://blog.csdn.net/weixin_43163153/article/details/132984167