23种设计模式之建造者模式

61 阅读3分钟

1. 什么是建造者模式

建造者模式(Builder Pattern)是 GoF 23种设计模式中对象创建型设计模式之一,其核心思想是把复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示。

2.为什么需要建造者模式

当对象的构造过程涉及多个步骤多个可选参数参数之间有依赖关系时,直接使用构造函数或工厂方法会导致:

  • 构造函数参数列表过长(telescoping constructor 反模式)
  • 可选参数组合爆炸
  • 对象状态不一致的风险
  • 可读性差,难以维护

3. 角色与UML

classDiagram
    class Computer {
        -cpu: String
        -ram: String
        -disk: String
        +setCpu(String)
        +setRam(String)
        +setDisk(String)
        +toString() String
    }

    class ComputerBuilder {
        #computer: Computer
        +buildCpu()* void
        +buildRam()* void
        +buildDisk()* void
        +getResult() Computer
    }

    class GamingComputerBuilder {
        +buildCpu() void
        +buildRam() void
        +buildDisk() void
    }

    class OfficeComputerBuilder {
        +buildCpu() void
        +buildRam() void
        +buildDisk() void
    }

    class Director {
        +construct(ComputerBuilder) Computer
    }

    class Client {
        +main(String[]) void
    }

    ComputerBuilder <|-- GamingComputerBuilder : extends
    ComputerBuilder <|-- OfficeComputerBuilder : extends
    ComputerBuilder --> Computer : creates/uses
    Director --> ComputerBuilder : uses
    Client --> Director : uses
    Client ..> GamingComputerBuilder : creates
    Client ..> OfficeComputerBuilder : creates
类 / 接口模式中的角色作用与职责
Computer产品(Product)被逐步装配的复杂对象;仅含 getter / setter,不感知建造过程。
ComputerBuilder抽象建造者(Builder)定义创建各部件的抽象接口;持有 / 返回产品实例。
GamingComputerBuilder具体建造者(ConcreteBuilder)实现抽象接口,给出游戏电脑各部件的具体装配算法;产出对应产品。
OfficeComputerBuilder具体建造者(ConcreteBuilder)实现抽象接口,给出办公电脑各部件的具体装配算法;产出对应产品。
Director指挥者(Director)持有抽象建造者引用,按固定顺序调用 buildXxx(),封装完整装配流程。
Client客户端(Client)选择具体建造者并交给 Director,最终取回完整产品;不依赖具体建造者细节。

4. Java代码示例

1、产品

public class Computer {
    private String cpu;
    private String ram;
    private String disk;

    public void setCpu(String cpu) { this.cpu = cpu; }
    public void setRam(String ram) { this.ram = ram; }
    public void setDisk(String disk) { this.disk = disk; }

    @Override
    public String toString() {
        return "Computer{cpu='" + cpu + "', ram='" + ram + "', disk='" + disk + "'}";
    }
}

2、抽象建造者

public abstract class ComputerBuilder {
    protected Computer computer = new Computer();

    public abstract void buildCpu();
    public abstract void buildRam();
    public abstract void buildDisk();

    public Computer getResult() { return computer; }
}

3、具体建造者

public class GamingComputerBuilder extends ComputerBuilder {
    public void buildCpu() { computer.setCpu("i9-13900K"); }
    public void buildRam() { computer.setRam("32GB DDR5"); }
    public void buildDisk() { computer.setDisk("2TB NVMe SSD"); }
}
public class OfficeComputerBuilder extends ComputerBuilder {
    public void buildCpu() { computer.setCpu("i5-12400"); }
    public void buildRam() { computer.setRam("16GB DDR4"); }
    public void buildDisk() { computer.setDisk("512GB SATA SSD"); }
}

4、指挥者

public class Director {
    public Computer construct(ComputerBuilder builder) {
        builder.buildCpu();
        builder.buildRam();
        builder.buildDisk();
        return builder.getResult();
    }
}

5、客户端

public class Client {
    public static void main(String[] args) {
        Director director = new Director();

        Computer gaming = director.construct(new GamingComputerBuilder());
        Computer office = director.construct(new OfficeComputerBuilder());

        System.out.println(gaming); // Computer{cpu='i9-13900K', ram='32GB DDR5', disk='2TB NVMe SSD'}
        System.out.println(office); // Computer{cpu='i5-12400', ram='16GB DDR4', disk='512GB SATA SSD'}
    }
}

运行结果

Computer{cpu='i9-13900K', ram='32GB DDR5', disk='2TB NVMe SSD'}
Computer{cpu='i5-12400', ram='16GB DDR4', disk='512GB SATA SSD'}

5. 优缺点

维度优点(Pros)缺点(Cons)
复杂性把“构建步骤”与“表示”分离,客户端无需了解装配细节,降低认知负担。类数量翻倍(Builder+ConcreteBuilder+Director),小系统容易过度设计。
扩展性新增产品时只加 ConcreteBuilder,符合开闭原则(OCP)。若装配算法本身多变,Director 会变得越来越臃肿,难以复用。
复用性同一 Director 可复用于不同 ConcreteBuilder,得到不同表示(游戏本/办公本)。Product 必须提供可写接口(setXxx),与“不可变对象”理念冲突,需额外拷贝。
一致性集中控制构造顺序与默认值,避免散落在各处 new 语句,保证对象完整性。多线程场景下,Builder 状态共享需额外同步,否则可能构造出“半成品”对象。
运行时可在运行期动态切换 ConcreteBuilder,实现“同流程、多产品”的灵活配置。对简单对象(字段<4)来说,代码量远大于直接构造函数或静态工厂,得不偿失。

6. 典型应用

  • OkHttp 连接池、拦截器、超时等复杂参数先写 Builder,真正 build() 时才生成不可变 OkHttpClient,可安全复用。
  • MyBatis 解析 XML 时按顺序 parse() → eval() → 封装成 Configuration,保证 Mapper 接口与 SQL 一次性绑定成功。

一句话总结:只要 配置项多、对象要不可变、构造过程要可扩展 这三个条件同时出现时可直接采用Builder模式。