建造者模式(结合mybatis源码)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

提示:这里可以添加本文要记录的大概内容:

今天在学习mybatis中的源码时,学习记录一下建造者模式,以便在遇到类似场景时可以学以致用。也希望可以帮助到各位靓仔🤵


提示:以下是本篇文章正文内容,下面案例可供参考

1、建造者模式的好处?

建造者模式是一种创建型设计模式,其主要目的是将一个复杂对象的构建过程和其表示分离,使得同样的构建过程可以创建不同的表示。这有助于隐藏构建细节,提高代码的可读性,并且在创建复杂对象时更加灵活。

2、例子说明

为了更好的理解mybatis中的建造者模式的运用,我会先举一个小demo对建造者模式进行阐述。

2.1 demon

举一个简单的例子,考虑构建一台计算机的场景。计算机有很多组件,例如 CPU、内存、硬盘等,而每种计算机的配置可能不同。建造者模式就可以用于将构建计算机对象的过程抽象成一个建造者,然后具体的建造者实现可以用于创建不同类型的计算机。

首先,我们定义一个计算机类:

java 复制代码
// Product:计算机类,表示最终构建的复杂对象
@Data
public class Computer {
    private String cpu;
    private String memory;
    private String hardDisk;
}

// Builder:抽象建造者接口,定义构建复杂对象的方法
public interface ComputerBuilder {
    void buildCPU(String cpu);
    void buildMemory(String memory);
    void buildHardDisk(String hardDisk);
    Computer getResult();
}

// ConcreteBuilder:具体建造者实现,实现具体的构建过程
public class DesktopComputerBuilder implements ComputerBuilder {
    private Computer computer = new Computer();

    @Override
    public void buildCPU(String cpu) {
        computer.setCpu(cpu);
    }

    @Override
    public void buildMemory(String memory) {
        computer.setMemory(memory);
    }

    @Override
    public void buildHardDisk(String hardDisk) {
        computer.setHardDisk(hardDisk);
    }

    @Override
    public Computer getResult() {
        return computer;
    }
}

// Director:指导者类,负责指导建造过程,即调用建造者的方法构建复杂对象
public class ComputerDirector {
    private ComputerBuilder computerBuilder;

    public ComputerDirector(ComputerBuilder builder) {
        this.computerBuilder = builder;
    }

    public Computer buildComputer(String cpu, String memory, String hardDisk) {
        computerBuilder.buildCPU(cpu);
        computerBuilder.buildMemory(memory);
        computerBuilder.buildHardDisk(hardDisk);
        return computerBuilder.getResult();
    }
}

然后,我们可以使用建造者模式来创建计算机对象:

java 复制代码
public class BuilderPatternExample {
    public static void main(String[] args) {
        // 创建具体建造者实例
        ComputerBuilder desktopBuilder = new DesktopComputerBuilder();
        
        // 创建指导者实例,并传入具体建造者
        ComputerDirector director = new ComputerDirector(desktopBuilder);
        
        // 调用指导者的方法构建复杂对象
        Computer desktopComputer = director.buildComputer("Intel i7", "16GB RAM", "1TB HDD");
        
        // 打印构建完成的计算机对象信息
        System.out.println("Desktop Computer Configuration:");
        System.out.println("CPU: " + desktopComputer.getCpu());
        System.out.println("Memory: " + desktopComputer.getMemory());
        System.out.println("Hard Disk: " + desktopComputer.getHardDisk());
    }
}

在这个例子中,DesktopComputerBuilder 是具体的建造者实现,ComputerDirector 是指导者。通过调用指导者的方法,我们可以使用具体的建造者构建出一个特定配置的计算机对象。这种方式使得构建过程和最终对象的表示相分离,使得代码更加灵活和易于维护。

2.2 Mybatis源码

下面是一段典型的通过sqlSession执行sql语句的流程

java 复制代码
public void test1() throws  Exception{
    // 1.获取配置文件
    InputStream in = Resources.getResourceAsStream("mybatis-config.xml");

    // 2.加载解析配置文件并获取SqlSessionFactory对象
    SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
    // 3.根据SqlSessionFactory对象获取SqlSession对象
    SqlSession sqlSession = factory.openSession();
    // 4.通过SqlSession中提供的 API方法来操作数据库
    List<User> list = sqlSession.selectList("com.boge.mapper.UserMapper.selectUserList");
    for (User user : list) {
        System.out.println(user);
    }
    // 5.关闭会话
    sqlSession.close();
}

这里的build方法便使用了建造者模式。接下来咱们分析一波,在分析之前我们需要再次明确建造者模式的核心思想:将复杂对象的表示和创建进行分离。

我们可以看到,是SqlSessionFactory是有默认的实现类的DefaultSqlSessionFactory

⚠️这里提个小问题:那为什么不直接采用DefaultSqlSessionFactory实现SqlSessionFactory,而采用了build方法呢?

  • 由于SqlSessionFactory在整体程序运行期间只需要创建一次,且全局配置文件和映射文件的加载解析也只需要一次,所以就把他们通过build方法一次搞定了。
  • 基于类的单一职责原则,我们不能把全局配置文件和映射文件的加载解析放到DefaultSqlSessionFactory中进行处理。

基于上述这两点我们就可以采用建造者模式进行解决。以下源码指截取了代表性的部分

下面DefaultSqlSessionFactory可以类比到上述的Computer类。

这里就是建造者模式中的表示!!

java 复制代码
public class DefaultSqlSessionFactory implements SqlSessionFactory {

  private final Configuration configuration;

  public DefaultSqlSessionFactory(Configuration configuration) {
    this.configuration = configuration;
  }

  @Override
  public SqlSession openSession() {
    return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
  }
}

下面这个就是建造者模式的创建!!

主要就是通过XMLConfigBuilderXMLMapperBuilder等建造者对全局配置文件和映射文件进行加载解析,并将解析完成后的对象保存到Configutation类的成员变量中。其实build(parser.parse())就是类似于demo中的指导者。

java 复制代码
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
    try {
      // 创建并初始化了 Configuration 对象
      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // 解析XML,将解析后的对象保存到configuration对象中,
      // 最终返回一个 DefaultSqlSessionFactory
      return build(parser.parse());
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error building SqlSession.", e);
    } finally {
      ErrorContext.instance().reset();
      try {
        inputStream.close();
      } catch (IOException e) {
        // Intentionally ignore. Prefer previous error.
      }
    }
  }

最后,在将configuration对象赋值给到DefaultSqlSessionFactory中的configuration属性。

java 复制代码
  public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
  }

上述就是将 DefaultSqlSessionFactory的表示和创建进行分离。

在 MyBatis 的实现中,并没有一个专门的指导者(Director)类。指导者模式通常用于组装复杂对象,而在 MyBatis 中,SqlSessionFactoryBuilder 兼具了指导者和建造者的角色。SqlSessionFactoryBuilder 负责整个 SqlSessionFactory 的构建过程,包括解析配置文件、创建 SqlSessionFactory 实例等。

在某些情况下,指导者模式可能会包含一个用于控制构建步骤顺序的指导者类,但在 MyBatis 中,这一部分的逻辑被整合到 SqlSessionFactoryBuilder 中了。因此,在 MyBatis 的设计中,并没有显式的指导者类。

三、 总结

这波属于是抛砖引玉了,希望大家在学习源码的过程中不仅是能够熟悉源码中的步骤,更重要的是在学习完后能够沉淀下来点东西能够提升自己程序设计的思想。要是有用的话记得点个赞👍,祝各位新的一年吃嘛嘛香、事事顺意🌹🌹

相关推荐
Daniel 大东13 分钟前
idea 解决缓存损坏问题
java·缓存·intellij-idea
wind瑞19 分钟前
IntelliJ IDEA插件开发-代码补全插件入门开发
java·ide·intellij-idea
HappyAcmen19 分钟前
IDEA部署AI代写插件
java·人工智能·intellij-idea
马剑威(威哥爱编程)25 分钟前
读写锁分离设计模式详解
java·设计模式·java-ee
鸽鸽程序猿26 分钟前
【算法】【优选算法】前缀和(上)
java·算法·前缀和
修道-032326 分钟前
【JAVA】二、设计模式之策略模式
java·设计模式·策略模式
九圣残炎32 分钟前
【从零开始的LeetCode-算法】2559. 统计范围内的元音字符串数
java·算法·leetcode
当归102444 分钟前
若依项目-结构解读
java
hlsd#1 小时前
关于 SpringBoot 时间处理的总结
java·spring boot·后端
iiiiiankor1 小时前
C/C++内存管理 | new的机制 | 重载自己的operator new
java·c语言·c++