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


    组合模式简介

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

    组合模式包含以下角色:

    1. Component(抽象构件):抽象构件可以是接口或抽象类,为叶子构件和容器构件对象声明接口,在该角色中可以包含所有子类公有行为的声明和实现,包括添加(add)、删除(remove)、获取子组件(getChildren)以及实现业务逻辑的方法(operation)。它是一个定义了公共的操作方法,可以用于管理和访问component子部件的抽象对象。
    2. Leaf(叶子构件):叶子构件在组合结构中表示叶子节点对象,叶子节点没有子节点,实现了抽象组件接口或抽象类,但没有子组件。对于那些访问及管理子构件的方法,可以通过异常等方式进行处理。叶子节点是树形结构中的最底层对象,通常包含具体的业务逻辑实现。
    3. Composite(树枝节点构件):枝节点构件在组合结构中表示容器节点对象,枝节点节点包含子节点,其子节点可以是叶子节点,也可以是其它枝节点,它提供一个集合用于存储子节点,实现了在抽象构件中定义行为,包括那些访问及管理子构件对方法,在其业务方法中可以递归调用其子节点对业务方法。并允许客户端以统一的方式处理其子组件。
    4. Client(客户类):使用组合模式来创建和操作复合对象结构。客户端代码不需要关心对象是叶子节点还是树枝节点,因为所有对象都通过抽象组件接口或抽象类来访问。

    组合模式优缺点:
    优点:

    1. 客户端代码可以一致地处理单个对象和组合对象,无需关心它们之间的区别。简化了客户端代码;
    2. 组合模式可以优化处理递归或分级数据结构,因为它将对象组织成树形结构,使得对对象的处理更加直观和高效。
    3. 容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”;

    缺点:

    1. 设计复杂性:组合模式可能使设计变得更加复杂,特别是当类之间的层次关系变得复杂时。客户端需要花更多时间来理解这些关系,从而正确地使用组合模式。
    2. 限制容器中的构件:在组合模式中,当需要添加新的容器构件或叶子构件时,可能很难对容器中的构件类型进行限制。这可能导致设计上的混乱和不必要的复杂性。
    3. 继承方法的限制:组合模式通常使用继承来实现,但这可能会限制新的构件只能通过继承来添加新功能。这可能限制了系统的灵活性和可扩展性。
    4. 依赖倒置原则的违反:在某些实现中,组合模式的叶子和树枝的声明可能是实现类而不是接口,这违反了依赖倒置原则。这可能导致代码之间的耦合度过高,不利于维护和扩展。

    使用场景

    1. 表示对象的部分和整体层次结构:当需要表示一个对象的部分以及整体层次结构时,组合模式是一个很好的选择。例如,在文件系统中,根目录下有若干文件和目录,在二级目录下还有目录和文件,这种情况下适合使用组合模式。
    2. 忽略组合对象与单个对象的差异:如果客户端需要忽略组合对象与单个对象的差异,以一致的方式处理它们,那么可以使用组合模式。这样,客户端代码可以简化,因为无需关心处理的是单个对象还是组合对象。
    3. 处理递归或分级数据结构:组合模式可以优化处理递归或分级数据结构。通过将对象组织成树形结构,组合模式使得对这些对象的处理更加直观和高效。

    通俗来讲就是:
    比如在现实生活中,存在很多“部分-整体”的关系。汽车与轮胎、发动机的关系。警察局与科室、警察的关系。学校与学院、学生、老师的关系。
    组合模式是一种非常普遍和常用的模式,接口服务互相组合,提供更丰富的接口,实现复杂的业务逻辑。一般情况会选择使用组合代替继承,组合更灵活、更方便。

    以下举一个组合模式的例子:
    假设学校中有校长管理老师,老师学生,通过以下实例演示学校中人员的层次结构:

    创建抽象类,组件Persion 【Component(组件)】

    import java.util.List;
    
    /**
     * Component(组件)
     *
     * 为组合中的对象声明接口
     * 声明一个接口用于访问和管理Component的子组件
     */
    
    public abstract class Persion {
        private String name;
        protected List<Persion> persionList;
    
        public abstract void add(Persion persion);
        public abstract void delete(Persion persion);
    
        public void input() {
            System.out.println(String.format("name is %s", name));
        };
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<Persion> getPersionList() {
            return persionList;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    创建具体类Principal【Composite(树枝节点构件)】

    import java.util.ArrayList;
    
    /**
     * Composite(树枝节点构件)
     *
     * 实现了在抽象构件中定义行为,包括那些访问及管理子构件对方法
     * 存储子部件
     *
     */
    public class Principal extends Persion {
        public Principal(String name) {
            setName(name);
            persionList = new ArrayList<Persion>();
        }
    
        @Override
        public void add(Persion persion) {
            persionList.add(persion);
        }
    
        @Override
        public void delete(Persion persion) {
            persionList.remove(persion);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    创建具体类Teacher【Composite(树枝节点构件)】

    import java.util.ArrayList;
    
    /**
     * Composite(树枝节点构件)
     *
     * 实现了在抽象构件中定义行为,包括那些访问及管理子构件对方法
     * 存储子部件
     *
     */
    public class Teacher extends Persion {
        public Teacher(String name) {
            setName(name);
            persionList = new ArrayList<Persion>();
        }
    
        @Override
        public void add(Persion persion) {
            persionList.add(persion);
        }
    
        @Override
        public void delete(Persion persion) {
            persionList.remove(persion);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    创建具体类Student【Leaf(叶子构件)】

    /**
     * Leaf(叶子构件)
     *
     * 叶子构件在组合结构中表示叶子节点对象,叶子节点没有子节点
     * 对于那些访问及管理子构件的方法,可以通过异常等方式进行处理
     */
    public class Student extends Persion{
        public Student(String name) {
            setName(name);
            persionList = null;
        }
    
        @Override
        public void add(Persion persion) {
        }
    
        @Override
        public void delete(Persion persion) {
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    创建测试类【Client(客户类)】

    /**
     * Client(客户类)
     * 使用组合模式来创建和操作复合对象结构
     *
    */
    public class Client {
        public static void main(String[] args) {
            Persion principal = new Principal("校长");
            Persion teacher1 = new Teacher("教师1");
            Persion teacher2 = new Teacher("教师2");
            Persion student1 = new Student("学生1");
            Persion student2 = new Student("学生2");
            Persion student3 = new Student("学生3");
            Persion student4 = new Student("学生4");
    
            principal.add(teacher1);
            principal.add(teacher2);
            teacher1.add(student1);
            teacher1.add(student2);
            teacher2.add(student3);
            teacher2.add(student4);
    
            info("无需", principal);
        }
    
        public static void info(String pre ,Persion persion){
            System.out.println(String.format("%s管理:%s", pre, persion.getName()));
    
            if(null == persion.getPersionList()){
                return;
            }
            for(Persion persion1 : persion.getPersionList()){
                info(persion.getName(), persion1);
            }
    
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    输出结果如下所示:

    无需管理:校长
    校长管理:教师1
    教师1管理:学生1
    教师1管理:学生2
    校长管理:教师2
    教师2管理:学生3
    教师2管理:学生4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    从结果可以看成功根据需求,获取到了校长管理老师,老师管理学生的层级结构。

    总而言之:
    组合模式,它是一种非常强大的结构型设计模式,用于创建复杂的对象结构,允许用户以统一的方式处理单个对象和复合对象。通过组合模式,你可以构建出具有层次结构的对象模型,这些对象可以像单个对象一样被简单、一致地使用。
    组合模式提供一个结构,可同时包容个别对象和组合对象;允许客户对个别对象以及组合对象一视同仁;组合结构内的任意对象称为组件;组件可以是组合,也可以是叶节点;在使用组合模式时,要多加考虑方式,有的时候可以与迭代器模式配合使用。


    以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git

  • 相关阅读:
    MySQL事务基本操作(方式1)
    前端小白科普:小程序组件与插件有啥区别?怎么用?
    自从用上这几款软件,才发现原来苹果电脑可以这么6!
    Git分支管理
    【Swift 60秒】61 - Computed properties
    前端HTML5 +CSS3 4.CSS基础 6 元素显示模式 && 7 CSS特性
    第十四章 使用Vercel部署在线文档
    【Git CMD】Git上传本地代码到远程仓库(6步到位)
    LeetCode88——合并两个有序数组
    每日汇评:黄金正在期待鲍威尔的讲话以获取新的方向动力
  • 原文地址:https://blog.csdn.net/qq_44307209/article/details/134478175