提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
提示:这里可以添加本文要记录的大概内容:
今天在学习mybatis中的源码时,学习记录一下建造者模式,以便在遇到类似场景时可以学以致用。也希望可以帮助到各位靓仔🤵
提示:以下是本篇文章正文内容,下面案例可供参考
建造者模式是一种创建型设计模式,其主要目的是将一个复杂对象的构建过程和其表示分离,使得同样的构建过程可以创建不同的表示。这有助于隐藏构建细节,提高代码的可读性,并且在创建复杂对象时更加灵活。
为了更好的理解mybatis
中的建造者模式的运用,我会先举一个小demo
对建造者模式进行阐述。
举一个简单的例子,考虑构建一台计算机的场景。计算机有很多组件,例如 CPU、内存、硬盘等,而每种计算机的配置可能不同。建造者模式就可以用于将构建计算机对象的过程抽象成一个建造者,然后具体的建造者实现可以用于创建不同类型的计算机。
首先,我们定义一个计算机类:
// 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();
}
}
然后,我们可以使用建造者模式来创建计算机对象:
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
是指导者。通过调用指导者的方法,我们可以使用具体的建造者构建出一个特定配置的计算机对象。这种方式使得构建过程和最终对象的表示相分离,使得代码更加灵活和易于维护。
下面是一段典型的通过sqlSession执行sql语句的流程
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
类。
这里就是建造者模式中的表示!!
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);
}
}
下面这个就是建造者模式的创建!!。
主要就是通过XMLConfigBuilder
和XMLMapperBuilder
等建造者对全局配置文件和映射文件进行加载解析,并将解析完成后的对象保存到Configutation
类的成员变量中。其实build(parser.parse())
就是类似于demo
中的指导者。
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
属性。
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
上述就是将 DefaultSqlSessionFactory
的表示和创建进行分离。
在 MyBatis 的实现中,并没有一个专门的指导者(Director)类。指导者模式通常用于组装复杂对象,而在 MyBatis 中,SqlSessionFactoryBuilder
兼具了指导者和建造者的角色。SqlSessionFactoryBuilder
负责整个 SqlSessionFactory
的构建过程,包括解析配置文件、创建 SqlSessionFactory
实例等。
在某些情况下,指导者模式可能会包含一个用于控制构建步骤顺序的指导者类,但在 MyBatis 中,这一部分的逻辑被整合到 SqlSessionFactoryBuilder
中了。因此,在 MyBatis 的设计中,并没有显式的指导者类。
这波属于是抛砖引玉了,希望大家在学习源码的过程中不仅是能够熟悉源码中的步骤,更重要的是在学习完后能够沉淀下来点东西能够提升自己程序设计的思想。要是有用的话记得点个赞👍,祝各位新的一年吃嘛嘛香、事事顺意🌹🌹