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模式更优的选择。

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

相关推荐
茂桑2 小时前
DDD领域驱动设计-基础设施层
设计模式·架构
shuair2 小时前
redis缓存预热、缓存击穿、缓存穿透、缓存雪崩
redis·spring·缓存
计算机程序设计小李同学2 小时前
基于 Spring Boot + Vue 的龙虾专营店管理系统的设计与实现
java·spring boot·后端·spring·vue
qq_12498707534 小时前
基于Java Web的城市花园小区维修管理系统的设计与实现(源码+论文+部署+安装)
java·开发语言·前端·spring boot·spring·毕业设计·计算机毕业设计
Chasmれ5 小时前
Spring Boot 1.x(基于Spring 4)中使用Java 8实现Token
java·spring boot·spring
计算机学姐5 小时前
基于SpringBoot的校园社团管理系统
java·vue.js·spring boot·后端·spring·信息可视化·推荐算法
落霞的思绪5 小时前
Spring AI Alibaba 集成 Redis 向量数据库实现 RAG 与记忆功能
java·spring·rag·springai
小温冲冲6 小时前
通俗且全面精讲工厂设计模式
设计模式
进击的小头6 小时前
设计模式与C语言高级特性的结合
c语言·设计模式
小温冲冲6 小时前
通俗且全面精讲单例设计模式
开发语言·javascript·设计模式