欢迎光临
我们一直在努力

23种设计模式一建造者模式‌

一、引言

建造者模式(Builder Pattern)是一种创建型设计模式,它将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。

核心问题

在日常开发中,我们经常需要创建包含多个组成部分的复杂对象,比如:

  • 电脑(CPU、内存、硬盘、显卡等)
  • 汽车(发动机、轮胎、座椅、车身等)
  • SQL查询(SELECT、FROM、WHERE、GROUP BY等)

如果使用传统的构造函数或setter方法创建这些对象,会遇到以下问题:

  • 构造函数参数过多:当对象包含很多可选参数时,构造函数会变得臃肿且难以维护
  • 参数顺序混乱:容易记错参数顺序,导致错误
  • 不可变对象构建困难:难以保持对象的不可变性
  • 构建逻辑耦合:对象的创建逻辑与业务逻辑混在一起

应用场景

建造者模式主要适用于以下场景:

  • 需要生成的对象具有复杂的内部结构
  • 需要生成的对象内部属性本身相互依赖
  • 对象的构建过程独立于该对象的组成部分和装配方式
  • 隔离复杂对象的创建和使用
  • 二、核心结构

    建造者模式包含四个核心角色:

    ┌─────────────────────────────────────────────────────────┐
    │ 指挥者 │
    │ Director │
    │ + construct() │
    └────────────────┬────────────────────────────────────────┘

    │ 指挥构建流程

    ┌─────────────────────────────────────────────────────────┐
    │ 抽象建造者 │
    │ Builder │
    │ + buildPartA() │
    │ + buildPartB() │
    │ + getResult() │
    └────────────────┬────────────────────────────────────────┘

    │ 继承/实现
    ┌────────┴────────┐
    ↓ ↓
    ┌──────────────┐ ┌──────────────┐
    │ 具体建造者A │ │ 具体建造者B │
    │ ConcreteBuilder│ │ ConcreteBuilder│
    │ + buildPartA() │ │ + buildPartA() │
    │ + buildPartB() │ │ + buildPartB() │
    │ + getResult() │ │ + getResult() │
    └──────┬───────┘ └──────┬───────┘
    │ │
    │ 构建 │ 构建
    ↓ ↓
    ┌──────────────┐ ┌──────────────┐
    │ 产品A │ │ 产品B │
    │ Product │ │ Product │
    └──────────────┘ └──────────────┘

    角色说明

    角色说明职责
    产品(Product) 最终要构建的复杂对象 包含多个组成部分,通常使用setter方法设置属性
    抽象建造者(Builder) 抽象接口或抽象类 定义创建产品各个部件的抽象方法
    具体建造者(ConcreteBuilder) 实现Builder接口 实现构建各个部件的具体逻辑,返回最终产品
    指挥者(Director) 指挥构建过程 按照特定顺序调用Builder的方法来构建产品

    关系说明

    • 产品是最终构建的目标对象
    • 抽象建造者定义了构建产品的抽象接口
    • 具体建造者实现了具体的构建逻辑
    • 指挥者控制构建的流程和顺序,但不直接参与构建

    三、实现步骤

    下面通过一个电脑组装的完整示例来演示建造者模式的实现:

    1. 定义产品类

    /**
    * 产品类:电脑
    */

    public class Computer {
    // 必需参数
    private String cpu;
    private String ram;

    // 可选参数
    private String storage;
    private String graphicsCard;
    private String operatingSystem;
    private String monitor;

    // 私有构造方法,只能通过Builder创建
    private Computer(Builder builder) {
    this.cpu = builder.cpu;
    this.ram = builder.ram;
    this.storage = builder.storage;
    this.graphicsCard = builder.graphicsCard;
    this.operatingSystem = builder.operatingSystem;
    this.monitor = builder.monitor;
    }

    // Getter方法
    public String getCpu() { return cpu; }
    public String getRam() { return ram; }
    public String getStorage() { return storage; }
    public String getGraphicsCard() { return graphicsCard; }
    public String getOperatingSystem() { return operatingSystem; }
    public String getMonitor() { return monitor; }

    @Override
    public String toString() {
    return "Computer{" +
    "cpu='" + cpu + '\\'' +
    ", ram='" + ram + '\\'' +
    ", storage='" + storage + '\\'' +
    ", graphicsCard='" + graphicsCard + '\\'' +
    ", operatingSystem='" + operatingSystem + '\\'' +
    ", monitor='" + monitor + '\\'' +
    '}';
    }

    /**
    * 静态内部类:Builder
    */

    public static class Builder {
    // 必需参数
    private final String cpu;
    private final String ram;

    // 可选参数 – 初始化为默认值
    private String storage = "256GB SSD";
    private String graphicsCard = "Integrated Graphics";
    private String operatingSystem = "Windows 11";
    private String monitor = "24 inch LCD";

    // 构造方法:必需参数
    public Builder(String cpu, String ram) {
    this.cpu = cpu;
    this.ram = ram;
    }

    // 链式调用设置可选参数
    public Builder storage(String storage) {
    this.storage = storage;
    return this;
    }

    public Builder graphicsCard(String graphicsCard) {
    this.graphicsCard = graphicsCard;
    return this;
    }

    public Builder operatingSystem(String operatingSystem) {
    this.operatingSystem = operatingSystem;
    return this;
    }

    public Builder monitor(String monitor) {
    this.monitor = monitor;
    return this;
    }

    // 构建最终产品
    public Computer build() {
    // 参数校验
    if (cpu == null || cpu.isEmpty()) {
    throw new IllegalArgumentException("CPU cannot be empty");
    }
    if (ram == null || ram.isEmpty()) {
    throw new IllegalArgumentException("RAM cannot be empty");
    }
    return new Computer(this);
    }
    }
    }

    2. 使用示例

    /**
    * 测试类
    */

    public class BuilderPatternDemo {
    public static void main(String[] args) {
    // 场景1:构建基础配置的电脑
    Computer basicComputer = new Computer.Builder(
    "Intel i5", "16GB"
    ).build();

    System.out.println("基础配置电脑:");
    System.out.println(basicComputer);
    System.out.println();

    // 场景2:构建游戏电脑(链式调用)
    Computer gamingComputer = new Computer.Builder(
    "Intel i9", "32GB"
    ).storage("1TB NVMe SSD")
    .graphicsCard("NVIDIA RTX 4090")
    .operatingSystem("Windows 11 Pro")
    .monitor("27 inch 4K IPS")
    .build();

    System.out.println("游戏配置电脑:");
    System.out.println(gamingComputer);
    System.out.println();

    // 场景3:构建办公电脑
    Computer officeComputer = new Computer.Builder(
    "AMD Ryzen 5", "8GB"
    ).storage("512GB SSD")
    .graphicsCard("AMD Radeon Graphics")
    .operatingSystem("Ubuntu 22.04")
    .build();

    System.out.println("办公配置电脑:");
    System.out.println(officeComputer);
    }
    }

    3. 输出结果

    基础配置电脑:
    Computer{cpu='Intel i5', ram='16GB', storage='256GB SSD',
    graphicsCard='Integrated Graphics', operatingSystem='Windows 11',
    monitor='24 inch LCD'}

    游戏配置电脑:
    Computer{cpu='Intel i9', ram='32GB', storage='1TB NVMe SSD',
    graphicsCard='NVIDIA RTX 4090', operatingSystem='Windows 11 Pro',
    monitor='27 inch 4K IPS'}

    办公配置电脑:
    Computer{cpu='AMD Ryzen 5', ram='8GB', storage='512GB SSD',
    graphicsCard='AMD Radeon Graphics', operatingSystem='Ubuntu 22.04',
    monitor='24 inch LCD'}

    四、优缺点分析

    优点

    优点说明
    解耦构建与表示 将复杂对象的构建过程与表示分离,相同的构建过程可以创建不同的表示
    代码可读性强 链式调用让代码更清晰,易于理解对象的创建过程
    支持可选参数 优雅地解决构造函数参数过多的问题,支持可选参数
    保证不可变性 通过私有构造器和final字段,可以轻松创建不可变对象
    灵活构建 可以逐步构建对象,支持不同的构建组合
    易于扩展 新增具体建造者无需修改现有代码,符合开闭原则

    缺点

    缺点说明
    代码量增加 需要创建Builder类,代码量相对增加
    性能开销 创建对象时需要先创建Builder,会有轻微性能影响
    适用范围受限 仅适用于复杂对象的创建,简单对象使用会显得过度设计

    五、应用场景

    1. 典型应用场景

    // 场景1:StringBuilder – JDK中的经典应用
    StringBuilder sb = new StringBuilder()
    .append("Hello")
    .append(" ")
    .append("World")
    .append("!")
    .toString();

    // 场景2:AlertDialog.Builder – Android开发
    new AlertDialog.Builder(context)
    .setTitle("提示")
    .setMessage("确定要删除吗?")
    .setPositiveButton("确定", (dialog, which) -> {})
    .setNegativeButton("取消", (dialog, which) -> {})
    .show();

    // 场景3:OkHttpClient – 网络请求
    OkHttpClient client = new OkHttpClient.Builder()
    .connectTimeout(10, TimeUnit.SECONDS)
    .readTimeout(30, TimeUnit.SECONDS)
    .addInterceptor(new LoggingInterceptor())
    .build();

    // 场景4:Lombok @Builder注解
    @Builder
    public class User {
    private String name;
    private Integer age;
    private String email;
    }
    // 使用:User user = User.builder().name("张三").age(25).build();

    2. 适用场景总结

    场景示例
    复杂对象创建 电脑、汽车、房屋等包含多个组件的对象
    多种组合配置 同一类产品有不同的配置组合
    逐步构建 需要分步骤创建的对象
    不可变对象 需要保证线程安全的不可变对象
    参数众多 包含很多可选参数的类

    六、与工厂模式的区别

    对比表格

    对比维度建造者模式工厂模式
    设计目的 分步构建复杂对象 批量创建同类对象
    关注点 对象的构建过程 对象的创建
    复杂度 适用于复杂对象 适用于简单对象
    参数设置 支持链式调用,灵活设置 通过构造函数或方法参数一次性设置
    构建方式 逐步构建,可以控制构建步骤 一步到位创建对象
    产品类型 可以创建不同类型的产品 通常创建同一类型的产品
    代码示例 User.builder().name("张三").age(25).build() UserFactory.createUser("张三", 25)

    核心区别

    // 工厂模式:关注创建,一步到位
    interface UserFactory {
    User createUser(String name, Integer age);
    }

    class DefaultUserFactory implements UserFactory {
    @Override
    public User createUser(String name, Integer age) {
    return new User(name, age);
    }
    }
    // 使用:User user = factory.createUser("张三", 25);

    // 建造者模式:关注构建过程,逐步设置
    class User {
    private String name;
    private Integer age;
    private String email;

    private User(Builder builder) {
    this.name = builder.name;
    this.age = builder.age;
    this.email = builder.email;
    }

    public static class Builder {
    private String name;
    private Integer age;
    private String email;

    public Builder name(String name) {
    this.name = name;
    return this;
    }

    public Builder age(Integer age) {
    this.age = age;
    return this;
    }

    public Builder email(String email) {
    this.email = email;
    return this;
    }

    public User build() {
    return new User(this);
    }
    }
    }
    // 使用:User user = new User.Builder().name("张三").age(25).email("test@example.com").build();

    七、最佳实践

    1. 使用建议

    /**
    * 建造者模式最佳实践示例
    */

    public class BestPracticeBuilder {

    // ✅ 推荐:使用静态内部类Builder
    public class GoodExample {
    private final String name;
    private final Integer age;

    private GoodExample(Builder builder) {
    this.name = builder.name;
    this.age = builder.age;
    }

    public static class Builder {
    private String name;
    private Integer age;

    public Builder name(String name) {
    this.name = name;
    return this;
    }

    public Builder age(Integer age) {
    this.age = age;
    return this;
    }

    public GoodExample build() {
    return new GoodExample(this);
    }
    }
    }

    // ✅ 推荐:在build()方法中进行参数校验
    public class GoodExampleWithValidation {
    private final String name;
    private final Integer age;

    private GoodExampleWithValidation(Builder builder) {
    this.name = builder.name;
    this.age = builder.age;
    }

    public static class Builder {
    private String name;
    private Integer age;

    public Builder name(String name) {
    this.name = name;
    return this;
    }

    public Builder age(Integer age) {
    this.age = age;
    return this;
    }

    public GoodExampleWithValidation build() {
    // 参数校验
    if (name == null || name.isEmpty()) {
    throw new IllegalArgumentException("name cannot be empty");
    }
    if (age == null || age < 0) {
    throw new IllegalArgumentException("age must be positive");
    }
    return new GoodExampleWithValidation(this);
    }
    }
    }
    }

    2. 注意事项

    注意事项说明
    参数校验 在build()方法中进行参数校验,而不是在setter方法中
    不可变性 使用final字段和私有构造方法保证对象不可变
    默认值 为可选参数设置合理的默认值
    返回类型 Builder的setter方法返回this,支持链式调用
    线程安全 建造者创建的对象通常是线程安全的
    合理使用 不要为所有类都创建Builder,仅适用于复杂对象

    3. 使用Lombok简化代码

    // 使用Lombok @Builder注解自动生成Builder类
    import lombok.Builder;
    import lombok.ToString;

    @Builder
    @ToString
    public class User {
    private final String name;
    private final Integer age;
    @Builder.Default
    private String email = "default@example.com";
    @Builder.Default
    private Boolean active = true;
    }

    // 使用方式
    public class Main {
    public static void main(String[] args) {
    User user = User.builder()
    .name("张三")
    .age(25)
    .email("zhangsan@example.com")
    .build();

    System.out.println(user);
    // 输出:User(name=张三, age=25, email=zhangsan@example.com, active=true)
    }
    }

    4. Spring中的建造者模式应用

    // Spring UriComponentsBuilder – URL构建
    import org.springframework.web.util.UriComponentsBuilder;

    String uri = UriComponentsBuilder.fromHttpUrl("https://api.example.com/users")
    .queryParam("page", 1)
    .queryParam("size", 10)
    .queryParam("sort", "id,desc")
    .build()
    .toUriString();

    // Spring ResponseEntity构建
    import org.springframework.http.ResponseEntity;

    ResponseEntity<String> response = ResponseEntity.ok()
    .header("Custom-Header", "value")
    .body("Success");

    八、总结

    建造者模式是一种非常实用的创建型设计模式,它通过将复杂对象的构建与表示分离,使得代码更加清晰、灵活、易于维护。

    核心要点回顾

  • 核心思想:分离构建与表示,支持链式调用
  • 适用场景:复杂对象创建、参数众多、需要不可变对象
  • 实现方式:静态内部类Builder + 私有构造方法
  • 注意事项:参数校验、不可变性、合理使用
  • 工具支持:Lombok @Builder注解简化代码
  • 选择建议

    • 需要复杂对象构建 → 使用建造者模式
    • 参数众多且可选 → 使用建造者模式
    • 需要不可变对象 → 使用建造者模式
    • 简单对象创建 → 使用工厂模式或构造函数
    • 大量同类对象创建 → 使用工厂模式
    赞(0)
    未经允许不得转载:171主机测评 » 23种设计模式一建造者模式‌
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址