Spring + 设计模式 (四) 创建型 - 建造者模式

建造者模式

引言

建造者模式是一种创建型设计模式,它将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。该模式通过分步骤构建对象,最终提供完整的成品,特别适用于具有多个组成部分的复杂对象。建造者模式既能保证对象的完整性,又能提供灵活的构建方式,是处理复杂对象创建的优雅解决方案。

实际开发中的用途

在实际开发中,建造者模式常用于以下场景:

  1. 需要创建包含多个部件的复杂对象(如HTML文档、报表等)
  2. 对象的构建过程需要分步骤进行
  3. 需要不同的对象表示但构建过程相似
  4. 希望隔离复杂对象的创建和使用

该模式解决了直接使用构造函数或setter方法创建复杂对象时面临的参数过多、构建逻辑混乱等问题,使代码更加清晰可维护。

Spring源码中的应用

Spring框架中广泛使用了建造者模式,一个典型的例子是UriComponentsBuilder类,用于构建URI组件。以下是Spring源码中的相关实现:

java 复制代码
// Spring框架中的UriComponentsBuilder
public class UriComponentsBuilder implements UriBuilder, Cloneable {
    private String scheme;
    private String userInfo;
    private String host;
    private int port = -1;
    private String path;
    private final MultiValueMap<String, String> queryParams = new LinkedMultiValueMap<>();
    private String fragment;

    // 私有构造函数
    private UriComponentsBuilder() {
    }

    // 静态工厂方法
    public static UriComponentsBuilder newInstance() {
        return new UriComponentsBuilder();
    }

    public static UriComponentsBuilder fromUri(URI uri) {
        return new UriComponentsBuilder().uri(uri);
    }

    // 各种构建方法
    public UriComponentsBuilder scheme(String scheme) {
        this.scheme = scheme;
        return this;
    }

    public UriComponentsBuilder host(String host) {
        this.host = host;
        return this;
    }

    // 最终构建方法
    public UriComponents build() {
        return new UriComponents(scheme, userInfo, host, port, path, queryParams, fragment);
    }
}

在这个实现中,UriComponentsBuilder提供了流畅的API来逐步构建URI的各个部分,最后通过build()方法生成不可变的UriComponents对象。这种设计使得URI的构建过程既灵活又安全,同时保持了代码的清晰性。

开发中的示例

考虑一个用户信息构建场景,用户对象包含姓名、年龄、地址、电话等多个属性,其中某些属性是必填的,某些是可选的。使用建造者模式可以清晰地表达哪些属性是必需的,哪些是可选的,并确保最终构建的用户对象是完整且一致的。

在实际开发中,MyBatis-Plus代码生成器常用于:

  1. 快速生成Entity、Mapper、Service、Controller等基础代码
  2. 统一项目代码风格和规范
  3. 减少重复CRUD代码编写时间
  4. 支持自定义模板生成特定结构代码

建造者模式在此场景中完美解决了代码生成配置复杂、可选参数多、生成过程需要分步控制等问题。

MyBatis-Plus源码中的应用

MyBatis-Plus的AutoGenerator类是建造者模式的典型实现。

以下是其核心源码结构:

java 复制代码
public class AutoGenerator {
    private DataSourceConfig dataSource;
    private GlobalConfig globalConfig;
    private PackageConfig packageInfo;
    private StrategyConfig strategy;
    private TemplateConfig template;
    private InjectionConfig injectionConfig;
    
    // 建造者方法
    public AutoGenerator setDataSource(DataSourceConfig dataSource) {
        this.dataSource = dataSource;
        return this;
    }
    
    public AutoGenerator setGlobalConfig(GlobalConfig globalConfig) {
        this.globalConfig = globalConfig;
        return this;
    }
    
    // 其他配置方法...
    
    // 执行生成
    public void execute() {
        // 生成逻辑实现...
    }
}

MyBatis-Plus代码生成器是建造者模式的工业级实践典范。通过将复杂的代码生成过程分解为多个可配置的构建步骤,它既保证了生成代码的质量,又提供了极大的灵活性。在实际开发中:

  1. 对于标准CRUD代码生成,直接使用默认配置即可
  2. 对于特殊需求,可以通过自定义模板和策略配置灵活扩展
  3. 建造者模式使得配置过程直观且类型安全
  4. 与Spring Boot的整合使其更加易用

掌握这种建造者模式的应用,可以极大提升开发效率,同时保证项目代码风格的一致性。

SpringBoot代码使用案例

以下是完整的Spring Boot 整合MyBatis-Plus代码生成器的实现:

java 复制代码
@Configuration
public class MybatisPlusGenerator {

    @Value("${spring.datasource.url}")
    private String url;
    
    @Value("${spring.datasource.username}")
    private String username;
    
    @Value("${spring.datasource.password}")
    private String password;

    /**
     * 代码生成器配置
     */
    @Bean
    public CommandLineRunner codeGenerator() {
        return args -> {
            // 1. 全局配置
            GlobalConfig globalConfig = new GlobalConfig.Builder()
                .outputDir(System.getProperty("user.dir") + "/src/main/java")
                .author("BuilderPatternDemo")
                .enableSwagger()
                .dateType(DateType.TIME_PACK)
                .commentDate("yyyy-MM-dd")
                .build();

            // 2. 数据源配置
            DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(url, username, password)
                .dbQuery(new MySqlQuery())
                .schema("mybatis_plus_demo")
                .typeConvert(new MySqlTypeConvert())
                .build();

            // 3. 包配置
            PackageConfig packageConfig = new PackageConfig.Builder()
                .parent("com.example.demo")
                .moduleName("system")
                .entity("entity")
                .mapper("mapper")
                .service("service")
                .serviceImpl("service.impl")
                .controller("controller")
                .pathInfo(Collections.singletonMap(OutputFile.xml, 
                    System.getProperty("user.dir") + "/src/main/resources/mapper"))
                .build();

            // 4. 策略配置
            StrategyConfig strategyConfig = new StrategyConfig.Builder()
                .addInclude("t_user", "t_order") // 要生成的表
                .addTablePrefix("t_") // 表前缀过滤
                .entityBuilder()
                    .enableLombok()
                    .enableChainModel()
                    .naming(NamingStrategy.underline_to_camel)
                    .columnNaming(NamingStrategy.underline_to_camel)
                    .logicDeleteColumnName("is_deleted")
                    .versionColumnName("version")
                    .addSuperEntityColumns("id", "create_time", "update_time")
                    .formatFileName("%sEntity")
                .mapperBuilder()
                    .enableBaseResultMap()
                    .enableBaseColumnList()
                    .formatMapperFileName("%sMapper")
                    .formatXmlFileName("%sMapper")
                .serviceBuilder()
                    .formatServiceFileName("%sService")
                    .formatServiceImplFileName("%sServiceImpl")
                .controllerBuilder()
                    .enableRestStyle()
                    .formatFileName("%sController")
                .build();

            // 5. 模板配置
            TemplateConfig templateConfig = new TemplateConfig.Builder()
                .disable(TemplateType.ENTITY)
                .entity("/templates/entity.java")
                .service("/templates/service.java")
                .serviceImpl("/templates/serviceImpl.java")
                .mapper("/templates/mapper.java")
                .xml("/templates/mapper.xml")
                .controller("/templates/controller.java")
                .build();

            // 6. 自定义配置
            InjectionConfig injectionConfig = new InjectionConfig.Builder()
                .beforeOutputFile((tableInfo, objectMap) -> {
                    // 生成前回调
                })
                .customMap(Collections.singletonMap("test", "MyBatis-Plus"))
                .customFile(Collections.singletonMap("DTO.java", "/templates/entityDTO.java.ftl"))
                .build();

            // 7. 执行生成
            new AutoGenerator(dataSourceConfig)
                .global(globalConfig)
                .packageInfo(packageConfig)
                .strategy(strategyConfig)
                .template(templateConfig)
                .injection(injectionConfig)
                .execute();
        };
    }
}

建造者模式的优势

  1. 配置清晰:每个配置项都有明确的构建方法,避免参数混乱
  2. 灵活性高:可以自由组合各种配置,满足不同需求
  3. 可读性强:链式调用使代码逻辑清晰易懂
  4. 扩展方便:新增配置项不影响现有结构
  5. 类型安全:编译时检查配置项的正确性

总结

建造者模式如同一位经验丰富的建筑师,将复杂对象的构建过程分解为清晰的步骤,最终交付一个结构完整的产品。在Spring生态中,从URI构建到配置组装,建造者模式的身影随处可见。它完美解决了复杂对象创建过程中的灵活性与安全性的矛盾,使代码既易于使用又便于维护。掌握建造者模式,开发者能够优雅地处理各种复杂对象的创建场景,构建出更加健壮、灵活的应用程序。记住:当面对具有多个组成部分的复杂对象时,建造者模式往往是比重叠构造器或JavaBean模式更优的选择。

(对您有帮助 && 觉得我总结的还行) -> 受累点个免费的赞👍,谢谢

相关推荐
浅陌sss1 小时前
设计模式 --- 外观模式
设计模式·c#
岁岁岁平安2 小时前
基于SpringBoot3实现MyBatis-Plus(SSMP)整合快速入门CURD(增删改查)
java·spring boot·spring·java-ee·mvc·mybatis·mybatis-plus
谢栋_5 小时前
设计模式从入门到精通之(五)观察者模式
观察者模式·设计模式
Miraitowa_cheems5 小时前
[Java EE] Spring 配置 和 日志
java·spring·java-ee
光头小小强0079 小时前
致远OA——自定义开发rest接口
java·经验分享·spring·tomcat
AI大模型顾潇9 小时前
[特殊字符] AI 大模型的 Prompt Engineering 原理:从基础到源码实践
运维·人工智能·spring·自然语言处理·自动化·大模型·prompt
魔道不误砍柴功10 小时前
Spring Boot自动配置原理深度解析:从条件注解到spring.factories
spring boot·后端·spring
蓝天居士11 小时前
软考 系统架构设计师系列知识点 —— 设计模式之创建者模式
设计模式·系统架构·建造者模式
暖苏12 小时前
Spring中IOC的重点理解(笔记)
java·开发语言·spring boot·笔记·后端·spring