XiaoLin's Blog

Xiao Lin

组合设计模式学习笔记

18
2024-02-26

组合设计模式介绍

组合设计模式(Composite Design Pattern)是一种结构型设计模式,它允许将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户端可以将一组单个对象当作一个单一的对象来处理,从而简化了客户端代码。

在组合模式中,每个对象都包含了一组子对象,这些子对象可以是其他组合对象或者叶子对象。客户端可以统一地对待组合对象和叶子对象,而不需要关心它们的具体类型。当客户端请求某个操作时,该操作会递归地在组合结构的子对象上执行,直到到达叶子对象。

组合模式的优点包括:

  1. 简化客户端代码:客户端无需关心对象的结构和组成,只需统一地处理组合对象和叶子对象。
  2. 提高代码的可扩展性:通过增加新的子类或组合对象,可以轻松地扩展系统的功能。
  3. 增强代码的复用性:组合模式允许将现有的对象组合成新的对象,从而避免了重复编写相似的代码。

组合模式的缺点包括:

  1. 增加系统的复杂性:由于引入了组合对象和叶子对象的概念,系统的结构和实现可能会变得更加复杂。
  2. 可能导致过度设计:在某些情况下,简单的对象继承关系可能已经足够满足需求,而引入组合模式可能会导致过度设计。

组合模式包含以下几个角色:

  1. Component(抽象构件):定义组合对象的通用接口,可以包含其他组合对象或叶子对象。
  2. Leaf(叶子节点):表示组合对象中的叶子节点,它没有子节点。
  3. Composite(组合节点):表示组合对象中的组合节点,它可以包含其他组合对象或叶子对象。

总之,组合模式是一种强大的设计模式,它可以帮助我们简化客户端代码,提高代码的可扩展性和复用性。然而,在使用组合模式时,我们需要权衡其带来的好处和增加的复杂性,确保它在解决特定问题时是合适的。

组合设计模式的实现

  • 抽象构建定义
package xyz.xiaolinz.demo.combination;

/**
 * 文件系统
 *
 * @author huangmuhong
 * @date 2023/11/30
 * @version 1.0.0
 *
 */
public interface FileSystem {

  /**
   * 展示
   *
   *
   *
   * @author huangmuhong
   * @date 2023/11/30
   * @since 1.0.0
   */
  void display();

}

  • 叶子节点定义
package xyz.xiaolinz.demo.combination;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

/**
 * 文件
 *
 * @author huangmuhong
 * @date 2023/11/30
 * @version 1.0.0
 * @see FileSystem
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class File implements FileSystem {


  private String fileName;

  private Long fileSize;


  @Override
  public void display() {
    System.out.println("文件名:" + fileName + ",文件大小:" + fileSize);
  }
}

  • 组合节点定义
package xyz.xiaolinz.demo.combination;

import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 文件夹
 *
 * @author huangmuhong
 * @date 2023/11/30
 * @version 1.0.0
 * @see FileSystem
 */
@AllArgsConstructor
@Data
@EqualsAndHashCode
public class Folder implements FileSystem {

  private String folderName;

  private List<FileSystem> fileSystemList;

  public Folder(String folderName) {
    this.folderName = folderName;
    fileSystemList = new ArrayList<>();
  }

  public void add(FileSystem fileSystem) {
    fileSystemList.add(fileSystem);
  }

  @Override
  public void display() {
    System.out.println("文件夹名:" + folderName);
    for (FileSystem fileSystem : fileSystemList) {
      fileSystem.display();
    }
  }
}

  • 具体调用
package xyz.xiaolinz.demo.combination;

/**
 * @author huangmuhong
 * @date 2023/11/30
 */
public class Main {

  public static void main(String[] args) {
    Folder fileSystem = new Folder("root");
    fileSystem.add(new File("file1", 1024L));
    fileSystem.add(new File("file2", 1024L));
    fileSystem.add(new File("file3", 1024L));

    Folder folder1 = new Folder("folder1");
    folder1.add(new File("file4", 1024L));
    folder1.add(new File("file5", 1024L));
    folder1.add(new File("file6", 1024L));

    fileSystem.add(folder1);

    fileSystem.display();
  }

}

  • 结果
    image.png

组合模式的设计思路,与其说是一种设计模式,倒不如说是对业务场景的一种数据结构和算法的抽象。其中,数据可以表示成树这种数据结构,业务需求可以通过在树上的递归遍历算法来实现。

组合模式,将一组对象组织成树形结构,将单个对象和组合对象都看做树中的节点,以统一处理逻辑,并且它利用树形结构的特点,递归地处理每个子树,依次简化代码实现。使用组合模式的前提在于,你的业务场景必须能够表示成树形结构。所以,组合模式的应用场景也比较局限,它并不是一种很常用的设计模式。

源码应用

jdk 源码

组合模式在 JDK 源码中也有很多应用。以下是一些常见的使用场景:

  1. Java Collection 框架:在 Java Collection 框架中,Collection 接口就是一个抽象构件,它定义了集合对象的通用接口。List、Set 和 Map 等具体集合类就是组合节点或叶子节点,用于存储和操作集合中的元素。
  2. Servlet API:在 Servlet API 中,ServletRequest 和 ServletResponse 接口就是一个抽象构件,它定义了 Servlet 的通用接口。HttpServletRequest 和 HttpServletResponse 等具体类就是组合节点或叶子节点,用于处理 Web 请求和响应。
    总之,组合模式在 JDK 源码中也有着广泛的应用,可以帮助开发者更加方便地操作各种层次结构。

ssm 源码

在 SSM(Spring + Spring MVC + MyBatis)框架中,组合模式也有一些应用场景,以下是一些常见的使用场景:

  1. Spring MVC:在 Spring MVC 中,Controller 就是一个组合节点,它可以包含其他组合对象或叶子对象,用于处理 Web 请求和响应。对于复杂的请求处理逻辑,可以将一个 Controller 分解成多个子 Controller,然后通过组合的方式将它们组合起来,使得请求处理逻辑更加清晰和易于维护。
  2. MyBatis:在 MyBatis 中,SqlNode 就是一个抽象构件,它定义了 SQL 节点的通用接口。WhereSqlNode、ChooseSqlNode、IfSqlNode 等具体类就是组合节点或叶子节点,用于构建 SQL 语句,解析动态 sql。