Java设计模式之java组合模式详解

Java组合模式详解

什么是组合模式?

组合模式是一种结构型设计模式,其主要思想是将对象组合成树形结构以表示“部分整体”的层次结构。组合模式中包含两种基本的组件:

  1. 叶节点(Leaf): 叶节点代表树的最底层的节点,即无子节点的节点。
  2. 复合节点(Composite): 复合节点代表树的非叶子节点,它可能包含子节点,也可能不包含。

组合模式的优点

  • 可以更方便地扩展对象结构;
  • 对象与对象集合使用起来方便一致;
  • 简化了实现客户端代码的复杂性。

Java组合模式的实现方式

我们可以通过抽象类和接口的方式进行组合模式的实现。以员工管理为例,假设员工管理有以下两种类型的员工:

  • 普通员工(Leaf节点)
  • 经理(Composite节点)

我们可以定义一个抽象类把员工类型进行统一。该类可以是抽象类或者是接口:

abstract class Employee {
    private String name;
    private Department department;

    public Employee(String name, Department department) {
        this.name = name;
        this.department = department;
    }

    public String getName() {
        return name;
    }

    public Department getDepartment() {
        return department;
    }

    // 其他操作
    // ...

    /**
     * 添加员工
     *
     * @param employee 新增员工
     */
    public void add(Employee employee) {
        throw new UnsupportedOperationException("add");
    }

    /**
     * 删除员工
     *
     * @param employee 删除的员工
     */
    public void remove(Employee employee) {
        throw new UnsupportedOperationException("remove");
    }

    /**
     * 打印员工
     *
     * @param depth 打印深度
     */
    public abstract void print(int depth);
}

在抽象类中,我们定义了员工的名称和所属部门属性,并定义了是否是叶子节点方法和添加、删除、打印操作的抽象方法。

在这个抽象类中,并没有实现添加、删除和打印的具体操作,因为普通员工没有子员工,所以这些操作不支持对普通员工的操作。而对于经理节点,因其下面有可能包含一些子员工,因此需要重写这些方法:

class Manager extends Employee {
    private List<Employee> employees = new ArrayList<>();

    public Manager(String name, Department department) {
        super(name, department);
    }

    /**
     * 添加员工
     *
     * @param employee 新增员工
     */
    @Override
    public void add(Employee employee) {
        employees.add(employee);
    }

    /**
     * 删除员工
     *
     * @param employee 删除的员工
     */
    @Override
    public void remove(Employee employee) {
        employees.remove(employee);
    }

    /**
     * 打印员工
     *
     * @param depth 打印深度
     */
    @Override
    public void print(int depth) {
        System.out.println("depth:" + depth + ", name:" + getName());
        for (Employee employee : employees) {
            employee.print(depth + 1);
        }
    }
}

在这个实现中,Manager继承了我们定义的Employee类,并且重写了add、remove和print操作。我们可以发现,其下面定义了员工列表,这个列表中可以添加其他的Employee类型实例,也就是说,Manager可以添加其他的经理和普通员工实例。

由于普通员工没有子员工,因此它可以不重写add、remove和print方法。

组合模式的使用场景

组合模式通常需要满足以下两个条件:

  1. 应用程序需要表示部分和整体层次关系;
  2. 应用程序需要从客户端比较同一组别的对象。

例如:

  • 文件系统的目录和文件;
  • 组织结构图和员工;
  • 菜单、子菜单和菜单项等界面元素。

例子一:组织结构图和员工

我们假设一个公司有多个部门,每个部门中有多个员工,公司最高管理者是CEO。我们可以用组合模式来表达出这些关系。

Department marketing = new Department("Marketing");
Department rd = new Department("Research and Development");
Department finance = new Department("Finance");

Employee ceo = new Manager("William", marketing);
Employee cto = new Manager("Marshall", rd);
Employee cfo = new Manager("Peeters", finance);

ceo.add(cto);
ceo.add(cfo);

Employee staff1 = new Manager("Andy", marketing);
Employee staff2 = new Manager("Simon", marketing);
Employee staff3 = new Manager("Kate", rd);
Employee staff4 = new Manager("Bob", finance);

cto.add(staff1);
cto.add(staff2);
cfo.add(staff3);
cfo.add(staff4);

ceo.print(0);

执行上述代码可以得到如下输出:

depth:0, name:William
depth:1, name:Marshall
depth:2, name:Andy
depth:2, name:Simon
depth:1, name:Peeters
depth:2, name:Kate
depth:2, name:Bob

例子二:煎饼糖果店销售情况

我们假设有一个煎饼糖果店,这家店面积不大,但是它有煎饼、糖果和饮料等多种商品,我们对这些商品进行销售管理。

MenuItem pancake = new MenuItem("Pancake", "A delicious pancake with maple syrup", 2.99);
MenuItem candy = new MenuItem("Candy", "Candy with many flavors", 1.99);
MenuItem drink = new MenuItem("Drink", "Drinks and juices", 0.99);
MenuComponent menu = new Menu("Menu");

menu.add(pancake);
menu.add(candy);
menu.add(drink);

MenuComponent combo = new Menu("Combo");

MenuItem pancakeCombo = new MenuItem("Pancake Combo", "A delicious pancake with maple syrup and coffee or tea", 4.99);
MenuItem candyCombo = new MenuItem("Candy Combo", "Candy with many flavors and coffee or tea", 3.99);

combo.add(pancakeCombo);
combo.add(candyCombo);
combo.add(drink);

menu.add(combo);

menu.print();

执行上述代码可以得到如下输出:

Menu:
    Pancake A delicious pancake with maple syrup    $2.99
    Candy   Candy with many flavors $1.99
    Drink   Drinks and juices   $0.99
    Combo:
        Pancake Combo   A delicious pancake with maple syrup and coffee or tea  $4.99
        Candy Combo Candy with many flavors and coffee or tea   $3.99
        Drink   Drinks and juices   $0.99

总结

组合模式主要用于树形结构的处理,它将对象组织成树形结构,并且能够以同样的方式处理单个对象以及对象集合,从而让客户端用一致性的方式处理对象。组合模式是设计渐进式的设计策略,即它允许我们逐步地将简单的对象组合成更为复杂的对象结构。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java设计模式之java组合模式详解 - Python技术站

(0)
上一篇 2023年5月26日
下一篇 2023年5月26日

相关文章

  • Java的Struts框架报错“PropertyNotFoundException”的原因与解决办法

    当使用Java的Struts框架时,可能会遇到“PropertyNotFoundException”错误。这个错误通常由以下原因之一起: 属性不存在:如果请求的属性不存在,则可能会出现此错误。在这种情况下,需要检查属性是否存在以解决此问题。 配置错误:如果配置文件中没有正确配置,则可能会出现此错误。在这种情况下,需要检查文件以解决此问题。 以下是两个实例: …

    Java 2023年5月5日
    00
  • java 实现 stack详解及实例代码

    Java 实现 Stack 详解及实例代码 什么是 Stack Stack(堆栈)是一种存储数据的结构,其遵循后进先出(LIFO)的原则。在 Stack 中,只有在栈顶的元素才能被访问、删除或更新,而其他的元素则需要等待栈顶元素先被操作。 Stack 的基本操作 Stack 可以执行以下操作: push:将数据项压入 stack 的顶部。 pop:弹出 st…

    Java 2023年5月26日
    00
  • Java用递归方法解决汉诺塔问题详解

    Java用递归方法解决汉诺塔问题详解 问题描述 汉诺塔问题的经典描述是:在有三根柱子的情况下,有三个大小不同的盘子从下往上按从大到小的顺序放在柱子A上,要将这三个盘子移动到柱子C上,要求每次只能移动一个盘子,且大盘子不能放在小盘子上面。 解题思路 汉诺塔问题是递归问题的典型,使用递归可以比较简单地解决该问题。 我们可以将解决汉诺塔问题的方法抽象为三个步骤: …

    Java 2023年5月19日
    00
  • Springboot自定义mybatis拦截器实现扩展

    下面是详细讲解“Springboot自定义mybatis拦截器实现扩展”的完整攻略。 什么是Mybatis拦截器 Mybatis拦截器是一种拦截器模式的机制,通过动态代理技术拦截方法的调用,在方法执行前后进行拦截处理。拦截器可以拦截Mybatis数据库访问层的所有操作,如SQL解析、SQL执行、结果集处理等。通过Mybatis拦截器机制,我们可以在方法调用前…

    Java 2023年5月20日
    00
  • Spring Boot实战教程之自动配置详解

    SpringBoot是一种基于Spring框架的快速开发应用程序的框架。它提供了大量自动配置和默认值,使开发人员可以更容易地构建出一个完整的Web应用程序。 自动配置是SpringBoot的一个重要特性。它可以减少开发人员的配置量,使得开发更加快捷。下面我们详细讲解一下“SpringBoot实战教程之自动配置详解”的攻略。 1.自动配置的原理 SpringB…

    Java 2023年5月15日
    00
  • Linux小技巧分享之如何重新启动tomcat

    接下来我将详细讲解关于“Linux小技巧分享之如何重新启动tomcat”的完整攻略。 什么是Tomcat? Tomcat是一个广泛使用的开源Web服务器,具备Servlet和JSP规范,由Apache基金会维护。 为什么需要重新启动Tomcat? 当我们修改了Tomcat中的配置文件或者部署了新的代码后,我们需要重新启动Tomcat才能使这些变更生效。 如何…

    Java 2023年6月2日
    00
  • Spring Security 过滤器注册脉络梳理

    下面是Spring Security 过滤器注册脉络梳理的完整攻略。 Spring Security 过滤器注册脉络梳理 在Spring Security中,过滤器的注册是非常重要的一项工作,它决定了Spring Security能否对请求进行拦截,并进行相应的安全控制。 过滤器链 Spring Security 采用了一条链式过滤器来完成安全控制,它是由一…

    Java 2023年5月20日
    00
  • Java中的八种基本数据类型详解

    Java中的八种基本数据类型详解 Java中的数据类型包括基本数据类型和引用数据类型,其中基本数据类型有八种,分别是byte、short、int、long、float、double、char和boolean。本篇文章我们将详细介绍这八种数据类型。 byte byte类型占用一个字节(8位),取值范围在-128到127之间。通常用于表示二进制数据,在网络传输和…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部