• 设计模式(八)组合


    一、定义#

    组合多个对象形成树形结构以表示具有部分-整体关系的层次结构。组合模式让客户端可以统一对待单个对象和组合对象。组合模式是一种结构型模式。

    二、描述#

    包含以下三个角色:1、Component(抽象构件):它可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象构件中定义了访问及管理它的子构件的方法,例如增加子构件、删除子构件、获取子构件等。
    2、Leaf(叶子构件):它在组合结构中表示叶子结点对象,叶子结点没有子节点,它实现了在抽象构件中定义的行为。对于那些访问及管理子构件的方法,可以通过抛出异常、提示错误等方式进行处理。
    3、Composite(容器构件):它在组合结构中表示容器节点对象,容器节点包含子节点,其子节点可以是叶子结点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义的行为,包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

    三、例子#

    X公司想要开发一个杀毒软件,该软件既可以针对某个文件夹杀毒,也可以针对某个指定的文件进行杀毒。该杀毒软件还可以根据各类文件的特点,为不同类型的文件提供不同的杀毒方式,例如图像文件(ImageFile)和文本文件(TextFile)的杀毒方式就有所差异。AbstractFile:抽象文件类,充当抽象构件

    public abstract class AbstractFile
    {
        public abstract void Add(AbstractFile file);
        public abstract void Remove(AbstractFile file);
        public abstract AbstractFile GetChild(int index);
        public abstract void KillVirus();
    }
    

    ImageFile、VideoFile、TextFile:图像文件、视频文件、文本文件类,充当叶子构件

    public class ImageFile : AbstractFile
    {
        private string name;
    
        public ImageFile(string name)
        {
            this.name = name;
        }
    
        public override void Add(AbstractFile file)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
        }
    
        public override void Remove(AbstractFile file)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
        }
    
        public override AbstractFile GetChild(int index)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
            return null;
        }
    
        public override void KillVirus()
        {
            // 此处模拟杀毒操作
            Console.WriteLine("**** 对图像文件‘{0}’进行杀毒", name);
        }
    }
    
    public class TextFile : AbstractFile
    {
        private string name;
    
        public TextFile(string name)
        {
            this.name = name;
        }
    
        public override void Add(AbstractFile file)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
        }
    
        public override void Remove(AbstractFile file)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
        }
    
        public override AbstractFile GetChild(int index)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
            return null;
        }
    
        public override void KillVirus()
        {
            // 此处模拟杀毒操作
            Console.WriteLine("**** 对文本文件‘{0}’进行杀毒", name);
        }
    }
    
    public class VideoFile : AbstractFile
    {
        private string name;
    
        public VideoFile(string name)
        {
            this.name = name;
        }
    
        public override void Add(AbstractFile file)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
        }
    
        public override void Remove(AbstractFile file)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
        }
    
        public override AbstractFile GetChild(int index)
        {
            Console.WriteLine("对不起,系统不支持该方法!");
            return null;
        }
    
        public override void KillVirus()
        {
            // 此处模拟杀毒操作
            Console.WriteLine("**** 对视频文件‘{0}’进行杀毒", name);
        }
    }
    

    Folder:文件夹类,充当容器构件

    public class Folder : AbstractFile
    {
        private IList fileList = new List();
        private string name;
    
        public Folder(string name)
        {
            this.name = name;
        }
    
        public override void Add(AbstractFile file)
        {
            fileList.Add(file);
        }
    
        public override void Remove(AbstractFile file)
        {
            fileList.Remove(file);
        }
    
        public override AbstractFile GetChild(int index)
        {
            return fileList[index];
        }
    
        public override void KillVirus()
        {
            // 此处模拟杀毒操作
            Console.WriteLine("---- 对文件夹‘{0}’进行杀毒", name);
    
            foreach (var item in fileList)
            {
                item.KillVirus();
            }
        }
    }
    

    Program:测试代码

    AbstractFile folder1 = new Folder("EDC的资料");
    AbstractFile folder2 = new Folder("图像文件");
    AbstractFile folder3 = new Folder("文本文件");
    AbstractFile folder4 = new Folder("视频文件");
    
    AbstractFile image1 = new ImageFile("小龙女.jpg");
    AbstractFile image2 = new ImageFile("张无忌.gif");
    
    AbstractFile text1 = new TextFile("九阴真经.txt");
    AbstractFile text2 = new TextFile("葵花宝典.doc");
    
    AbstractFile video1 = new VideoFile("笑傲江湖.rmvb");
    AbstractFile video2 = new VideoFile("天龙八部.mp4");
    
    folder2.Add(image1);
    folder2.Add(image2);
    
    folder3.Add(text1);
    folder3.Add(text2);
    
    folder4.Add(video1);
    folder4.Add(video2);
    
    folder1.Add(folder2);
    folder1.Add(folder3);
    folder1.Add(folder4);
    
    folder1.KillVirus();
    

    四、总结#

    1、优点

    (1)可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使客户忽略了层次的差异,方便对整个层次结构进行控制。
    (2)客户端可以一致地使用一个组合结构或其中单个对象,不必关心是单个对象还是整个结构,简化代码。
    (3)增加新的容器构件和叶子构件都十分方便,无需对现有类库代码进行任何修改,符合开闭原则。
    (4)为树形结构的面向对象实现提供了灵活地解决方案,可以形成复杂的树形结构,但对树形结构的控制却很简单。

    2、缺点

    (1)增加新构件时很难对容器中的构建类型进行限制。

  • 相关阅读:
    JUC常见类,线程池基础及死锁问题
    第14篇ESP32 idf wifi联网_WiFi STA 模式(连接到WIFI)LCD ST7920液晶屏显示
    PostgreSQL教程(十七):SQL语言(十)之性能提示
    在线教育系统,引领了全新的教学模式
    Ubuntu安装boost
    MySql
    uni-appH5修改端口号
    【剑指offer|图解|双指针】训练计划 I + 删除有序数组中的重复项
    分布式加/解密的敏感数据的保护方案的安全性证明及应用场景
    【单片机学习的准备】
  • 原文地址:https://www.cnblogs.com/WinterSir/p/17341199.html