【从零入门23种设计模式03】创建型之建造者模式(简易版与导演版)

一、建造者模式的核心定义

建造者模式是一种创建型设计模式 ,核心思想是:将复杂对象的构建过程与它的表示分离,使得同样的构建流程可以创建出不同的对象实例。

简单比喻:就像你去奶茶店点奶茶 ------ 构建一杯奶茶的 "流程" 是固定的(选基底、选甜度、选配料、加冰 / 热),但每一步的 "具体选择" 可以不同(比如基底选红茶 / 绿茶,甜度选三分 / 五分),最终能做出不同口味的奶茶。建造者模式就是把 "流程(步骤)" 和 "具体实现(选择)" 分开,让构建过程更清晰、灵活。

二、为什么需要建造者模式?

它主要解决以下问题
  1. 避免 "臃肿的构造函数" :当一个对象有很多属性(尤其是可选属性)时,直接用构造函数会导致参数列表过长(比如 new Computer("i9", 32, "1T", "4090", "Windows")),可读性差且易出错;
  2. 保证对象状态统一 :如果用 setter 方法逐个设置属性,对象在构造过程中可能处于 "不完整状态"(比如只设了 CPU 没设内存就被调用);
  3. 解耦构建流程和细节:构建步骤固定,但每个步骤的实现可灵活替换,便于扩展。
优点
  • 分离构建过程和表示,使得构建过程更加灵活,可以构建不同的表示。
  • 可以更好地控制构建过程,隐藏具体构建细节。
  • 代码复用性高,可以在不同的构建过程中重复使用相同的建造者。
缺点
  • 如果产品的属性较少,建造者模式可能会导致代码冗余。
  • 增加了系统的类和对象数量。

三、建造者模式的核心角色

角色 作用
产品(Product) 要构建的复杂对象(比如电脑、奶茶、汽车)
抽象建造者(Builder) 定义构建产品的所有步骤(比如 "设置 CPU""设置内存"),通常是接口 / 抽象类
具体建造者(ConcreteBuilder) 实现抽象建造者的方法,完成具体产品的构建(比如 "游戏本建造者""办公本建造者")
指挥者(Director) 可选角色,负责按固定顺序调用建造步骤,控制整体构建流程

四、代码示例(Java 实现)

以 "构建电脑" 为例,电脑有必选属性(CPU、内存)和可选属性(硬盘、显卡、系统),用建造者模式实现:

1. 产品类(Computer)
复制代码
// 要构建的复杂对象:电脑
public class Computer {
    // 必选属性
    private String cpu;
    private int ram;
    // 可选属性
    private String hardDisk;
    private String graphicsCard;
    private String os;

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

    // 静态内部建造者类(最常用的简化写法,省略Director)
    public static class Builder {
        // 必选属性(必须在Builder构造时传入)
        private String cpu;
        private int ram;
        // 可选属性(默认值或按需设置)
        private String hardDisk = "512G SSD"; // 默认硬盘
        private String graphicsCard = "集成显卡"; // 默认显卡
        private String os = "Windows 10"; // 默认系统

        // Builder构造方法:强制传入必选属性
        public Builder(String cpu, int ram) {
            this.cpu = cpu;
            this.ram = ram;
        }

        // 可选属性的设置方法,返回Builder本身(链式调用)
        public Builder hardDisk(String hardDisk) {
            this.hardDisk = hardDisk;
            return this;
        }

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

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

        // 构建方法:创建Computer实例
        public Computer build() {
            // 可选:在这里做参数校验,确保对象完整
            if (cpu == null || ram <= 0) {
                throw new IllegalArgumentException("CPU和内存不能为空!");
            }
            return new Computer(this);
        }
    }

    // 重写toString,方便查看结果
    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram=" + ram + "G" +
                ", hardDisk='" + hardDisk + '\'' +
                ", graphicsCard='" + graphicsCard + '\'' +
                ", os='" + os + '\'' +
                '}';
    }
}
2. 测试代码(使用建造者创建对象)
复制代码
public class BuilderTest {
    public static void main(String[] args) {
        // 构建"办公本":只用必选属性+默认可选属性
        Computer officeComputer = new Computer.Builder("i5-13400", 16)
                .build();
        System.out.println("办公本:" + officeComputer);

        // 构建"游戏本":必选属性+自定义可选属性(链式调用)
        Computer gameComputer = new Computer.Builder("i9-14900K", 32)
                .hardDisk("2T SSD")
                .graphicsCard("RTX 4090")
                .os("Windows 11")
                .build();
        System.out.println("游戏本:" + gameComputer);
    }
}
3. 运行结果
复制代码
办公本:Computer{cpu='i5-13400', ram=16G, hardDisk='512G SSD', graphicsCard='集成显卡', os='Windows 10'}
游戏本:Computer{cpu='i9-14900K', ram=32G, hardDisk='2T SSD', graphicsCard='RTX 4090', os='Windows 11'}

五、代码关键说明

  • 私有化产品构造方法:确保只能通过 Builder 创建对象,避免对象状态不完整;

    // 私有化构造方法,只能通过Builder创建Computer实例
    private Computer(Builder builder) {
    this.cpu = builder.cpu;
    this.ram = builder.ram;
    this.hardDisk = builder.hardDisk;
    this.graphicsCard = builder.graphicsCard;
    this.os = builder.os;
    }

核心作用:禁止外部通过new Computer()直接创建对象 ,必须通过内部的Builder类来创建,保证对象创建的可控性;

赋值逻辑:从Builder对象中读取配置好的属性值,赋值给Computer的属性(Builder 相当于 "配置器")。

  • 静态内部 Builder 类:这是最常用的简化写法(省略 Director),符合 "迪米特法则";

Builder 的构造方法(强制传入必选属性)
复制代码
// Builder构造方法:强制传入必选属性
public Builder(String cpu, int ram) {
    this.cpu = cpu;
    this.ram = ram;
}

核心作用:强制要求创建 Builder 时必须传入 CPU 和内存,从源头保证必选属性不缺失;

举例:如果写new Computer.Builder()会直接编译报错,必须写new Computer.Builder("i5", 16)

  • 链式调用 :每个可选属性的设置方法返回this,让代码更简洁(builder.xx().yy().build());

    // 可选属性的设置方法,返回Builder本身(链式调用)
    public Builder hardDisk(String hardDisk) {
    this.hardDisk = hardDisk;
    return this;
    }

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

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

核心设计:每个方法执行完属性赋值后,返回this(当前 Builder 对象),这是 "链式调用" 的关键;

效果:可以写builder.hardDisk("2T SSD").graphicsCard("RTX4090").os("Windows11"),代码简洁且可读性高;

对比:如果不返回this,需要写builder.hardDisk("2T SSD"); builder.graphicsCard("RTX4090");,代码冗余。

  • 参数校验 :在build()方法中校验必选属性,保证对象合法性。

    // 构建方法:创建Computer实例
    public Computer build() {
    // 可选:在这里做参数校验,确保对象完整
    if (cpu == null || ram <= 0) {
    throw new IllegalArgumentException("CPU和内存不能为空!");
    }
    return new Computer(this);
    }

核心作用:触发Computer对象的创建,是建造者模式的 "收尾步骤";

参数校验:额外增加合法性检查(比如 CPU 不能为 null、内存不能≤0),即使通过了 Builder 构造方法,也能防止传入非法值(比如new Builder(null, -8));

异常类型:IllegalArgumentException是 Java 标准异常,用于表示 "参数不合法",符合语义。

六、建造者模式的实际应用场景

  1. SDK / 框架设计 :比如 Java 的StringBuilder(本质是简化的建造者模式,构建复杂字符串)、MyBatis 的SqlSessionFactoryBuilder
  2. 复杂对象创建:比如创建订单(包含收货人、商品、支付方式、物流等多属性)、配置对象(比如连接池配置);
  3. 生成器工具:比如 JSON/XML 生成器(固定的构建步骤,不同内容对应不同表示)。

七、总结

  1. 建造者模式的核心是分离 "构建步骤" 和 "具体实现",解决复杂对象的创建问题;
  2. 最常用的形式是静态内部 Builder 类 + 链式调用,无需单独的 Director 角色,简洁易用;
  3. 它的核心价值是保证对象创建的灵活性和安全性,避免臃肿构造函数和不完整对象

八、扩展

一、带 Director 角色的完整建造者模式(Java 实现)

带 Director 的版本更贴合建造者模式的经典定义,Director 负责 "把控构建流程",具体建造者负责 "实现构建细节",完全解耦流程和实现。依然以 "构建电脑" 为例:

1. 产品类(Product):Computer
复制代码
// 要构建的复杂对象:电脑(和之前一致,仅调整访问权限适配Builder)
public class Computer {
    private String cpu;
    private int ram;
    private String hardDisk;
    private String graphicsCard;
    private String os;

    // 空构造(让Builder可以设置属性)
    public Computer() {}

    // setter方法(供Builder调用)
    public void setCpu(String cpu) {
        this.cpu = cpu;
    }

    public void setRam(int ram) {
        this.ram = ram;
    }

    public void setHardDisk(String hardDisk) {
        this.hardDisk = hardDisk;
    }

    public void setGraphicsCard(String graphicsCard) {
        this.graphicsCard = graphicsCard;
    }

    public void setOs(String os) {
        this.os = os;
    }

    @Override
    public String toString() {
        return "Computer{" +
                "cpu='" + cpu + '\'' +
                ", ram=" + ram + "G" +
                ", hardDisk='" + hardDisk + '\'' +
                ", graphicsCard='" + graphicsCard + '\'' +
                ", os='" + os + '\'' +
                '}';
    }
}
2. 抽象建造者(Builder):ComputerBuilder

定义构建电脑的所有核心步骤,是具体建造者的 "规范":

复制代码
// 抽象建造者:定义构建电脑的所有步骤
public abstract class ComputerBuilder {
    // 持有产品对象,供子类设置属性
    protected Computer computer = new Computer();

    // 必选构建步骤(抽象方法,子类必须实现)
    public abstract void buildCpu();
    public abstract void buildRam();

    // 可选构建步骤(默认实现,子类可重写)
    public void buildHardDisk() {
        computer.setHardDisk("512G SSD"); // 默认值
    }

    public void buildGraphicsCard() {
        computer.setGraphicsCard("集成显卡"); // 默认值
    }

    public void buildOs() {
        computer.setOs("Windows 10"); // 默认值
    }

    // 构建完成,返回产品
    public Computer getComputer() {
        return computer;
    }
}
3. 具体建造者(ConcreteBuilder)

实现抽象建造者的步骤,完成 "游戏本" 和 "办公本" 的具体构建:

复制代码
// 具体建造者1:游戏本建造者
public class GameComputerBuilder extends ComputerBuilder {
    @Override
    public void buildCpu() {
        computer.setCpu("i9-14900K"); // 游戏本高性能CPU
    }

    @Override
    public void buildRam() {
        computer.setRam(32); // 游戏本32G内存
    }

    // 重写可选步骤,自定义游戏本配置
    @Override
    public void buildHardDisk() {
        computer.setHardDisk("2T SSD");
    }

    @Override
    public void buildGraphicsCard() {
        computer.setGraphicsCard("RTX 4090");
    }

    @Override
    public void buildOs() {
        computer.setOs("Windows 11");
    }
}

// 具体建造者2:办公本建造者
public class OfficeComputerBuilder extends ComputerBuilder {
    @Override
    public void buildCpu() {
        computer.setCpu("i5-13400"); // 办公本中等CPU
    }

    @Override
    public void buildRam() {
        computer.setRam(16); // 办公本16G内存
    }

    // 可选步骤用默认值,无需重写
}
4. 指挥者(Director)

负责固定构建流程,调用建造者的步骤,控制 "先建什么、后建什么":

复制代码
// 指挥者:控制电脑的构建流程
public class ComputerDirector {
    // 构建方法:传入具体建造者,按固定流程构建
    public Computer constructComputer(ComputerBuilder builder) {
        // 固定构建顺序:CPU → 内存 → 硬盘 → 显卡 → 系统
        builder.buildCpu();
        builder.buildRam();
        builder.buildHardDisk();
        builder.buildGraphicsCard();
        builder.buildOs();
        return builder.getComputer();
    }
}
5. 测试代码(使用 Director 构建对象)
复制代码
public class DirectorBuilderTest {
    public static void main(String[] args) {
        // 1. 创建指挥者
        ComputerDirector director = new ComputerDirector();

        // 2. 构建游戏本:传入游戏本建造者
        ComputerBuilder gameBuilder = new GameComputerBuilder();
        Computer gameComputer = director.constructComputer(gameBuilder);
        System.out.println("游戏本:" + gameComputer);

        // 3. 构建办公本:传入办公本建造者
        ComputerBuilder officeBuilder = new OfficeComputerBuilder();
        Computer officeComputer = director.constructComputer(officeBuilder);
        System.out.println("办公本:" + officeComputer);
    }
}
6. 运行结果
复制代码
游戏本:Computer{cpu='i9-14900K', ram=32G, hardDisk='2T SSD', graphicsCard='RTX 4090', os='Windows 11'}
办公本:Computer{cpu='i5-13400', ram=16G, hardDisk='512G SSD', graphicsCard='集成显卡', os='Windows 10'}

关键说明(Director 的作用)

  • Director 是 "流程指挥官":它定义了 "先建 CPU、再建内存、最后建系统" 的固定流程,不管传入哪个具体建造者,都按这个流程构建;
  • 具体建造者是 "细节执行者":只负责实现每个步骤的具体内容(比如游戏本用 i9,办公本用 i5);
  • 扩展灵活:如果要新增 "轻薄本",只需新增LightComputerBuilder,无需修改 Director 和其他代码(符合开闭原则)。

二、建造者模式 vs 工厂模式(核心区别)

很多新手会混淆这两种创建型模式,核心差异在于 "创建的关注点" 和 "使用场景",用表格和通俗比喻清晰对比:

维度 建造者模式 工厂模式(简单工厂 / 工厂方法 / 抽象工厂)
核心目的 构建复杂对象(多属性、多步骤),控制构建流程 创建简单 / 复杂对象,快速获取实例
创建方式 分步骤构建(一步步设置属性 / 组件),最后组装成对象 一次性创建(调用方法直接返回完整对象)
关注点 关注 "如何构建"(步骤、流程、细节) 关注 "创建谁"(选择哪个对象实例)
对象属性灵活性 高:可自定义多个可选属性,支持链式配置 低:通常返回固定配置的对象
代码特征 有明确的 "步骤方法"+"build/construct" 方法 有明确的 "工厂方法"(如createXXX()
通俗比喻 拼乐高:按步骤拼出不同造型(流程固定,零件可选) 去便利店买水:说 "买矿泉水" 直接拿到,不用管怎么生产
典型使用场景 1. 多属性对象(订单、配置、电脑)2. 需控制构建流程3. 避免臃肿构造函数 1. 快速创建单一类型对象(如ShapeFactory.createCircle())2. 解耦对象创建和使用3. 统一对象创建入口
典型例子 StringBuilder、MyBatis 的SqlSessionFactoryBuilder、OkHttp 的Request.Builder Calendar.getInstance()、Spring 的BeanFactory、简单工厂创建图形
补充:何时选建造者,何时选工厂?
  • 如果你需要自定义对象的多个属性(比如电脑的 CPU、内存、显卡都要选)→ 用建造者模式;
  • 如果你只需要获取一个固定类型的对象(比如 "我要一个圆形""我要一个 MySQL 连接池")→ 用工厂模式;
  • 建造者模式是 "定制化生产",工厂模式是 "标准化量产"。

总结
  1. 带 Director 的建造者模式:通过 "抽象 Builder 定步骤、具体 Builder 做实现、Director 控流程",完全解耦构建流程和细节,适合需要统一构建流程的场景;
  2. 简化版建造者(静态内部类):省略 Director,通过链式调用直接构建,更简洁,日常开发中使用更广;
  3. 建造者 vs 工厂:核心差异是 "分步骤定制构建" vs "一次性标准化创建",前者关注 "怎么建",后者关注 "建什么"。
相关推荐
小李独爱秋1 小时前
模拟面试:不能关机的情况下 , 如果挂载目录卸载不掉应该怎么办?
linux·运维·面试·职场和发展·操作系统·文件系统
汤姆yu2 小时前
基于springboot的健身爱好者打卡与互动交流系统
java·spring boot·后端
专业开发者2 小时前
Wi-Fi 技术学习:基于 IEEE 802.11ax 的 MU-OFDMA 触发帧结构与抓包解析
学习
jaysee-sjc2 小时前
十三、Java入门进阶:异常、泛型、集合与 Stream 流
java·开发语言·算法
百锦再2 小时前
Java Map常用方法和实现类深度详解
java·开发语言·spring boot·struts·kafka·tomcat·maven
_codemonster2 小时前
JavaWeb开发系列(九)idea配置jdbc
java·ide·intellij-idea
Hx_Ma162 小时前
测试题(六)
java·tomcat·mybatis
人道领域2 小时前
SpringBoot vs SpringMVC:以及SpringBoot的全流程开发(1)
java·spring boot·spring
码云数智-大飞2 小时前
.NET 10 & C# 14 新特性详解:扩展成员 (Extension Members) 全面指南
java·数据库·算法