建造者模式概述

建造者模式可以将部件本身和它们的组装过程分开,关注如何一步一步地创建一个包含多个组成部分的复杂对象。用户只需要指定对象的类型即可得到该对象,而无需知道其内部的具体构造细节。

定义: 建造者模式:讲一个复杂对象的构建于它的表示分离,使得同样的构建过程可以创建不同的表示。

建造者模式是一种对象创建型模式,它将客户端与包含多个部件的复杂对象的创建过程分离,客户端无需知道复杂对象的内部组成部分与装配方式,只需要知道所需建造者的类型即可。

建造者模式的结构与实现

建造者模式的结构

2bae9ac00bd7f6681d3d68884b436e28.png

建造者模式包含以下四个角色:

Builder(抽象建造者):它为创建一个产品对象各个部件指定抽象接口,在该接口中一般声明两类方法。一类方法是buildPartX(),他们用来创建复杂对象的各个部件;另一类方法是getResult(),他们用于返回复杂对象。Builder既可以是抽象类,也可以是接口。

ConcreteBuilder(具体建造者):它实现了Builder接口,实现各个部件的具体构造和装配方法,定义并明确所创建的复杂对象,还可以提供一个方法返回创建好的复杂产品对象。

Product(产品):它是构被构建的复杂对象,包含多个组成部件,具体建造者创建该产品的内部表示并定义它的装配过程。

Director(指挥者):指挥者又被称为导员类,它负责安排复杂对象的建造次序,指挥者与抽象建造者之间存在着关联关系 ,可以在其consttruct()建造方法中调用建造者对象的部件构造与装配方法,完成复杂对象的建造。客户端一般只需要与指挥者进行交互,在客户端确定具体建造者的类型,并实例化具体建造者对象,然后通过指挥者类的构造函数或者Setter方法将对象传入指挥者类中。

建造者模式的实现

构建电脑为例,展示建造者模式的具体实现(使用Java伪代码):

1. 产品类:Computer

包含多个部件,代表最终被构建的对象。

class Computer {
    private String cpu;    // CPU部件
    private String memory; // 内存部件
    private String disk;   // 硬盘部件
 
    // 部件的setter方法
    public void setCpu(String cpu) { this.cpu = cpu; }
    public void setMemory(String memory) { this.memory = memory; }
    public void setDisk(String disk) { this.disk = disk; }
 
    // 显示产品信息
    public void showInfo() {
        System.out.println("电脑配置:CPU=" + cpu + ", 内存=" + memory + ", 硬盘=" + disk);
    }
}
2. 抽象建造者:IComputerBuilder

定义构建电脑的抽象步骤。

interface IComputerBuilder {
    void buildCpu();    // 构建CPU
    void buildMemory(); // 构建内存
    void buildDisk();   // 构建硬盘
    Computer getComputer(); // 返回最终产品
}
3. 具体建造者:LenovoBuilder & DellBuilder

实现抽象接口,完成具体品牌电脑的部件构建。

// 联想电脑建造者
class LenovoBuilder implements IComputerBuilder {
    private Computer computer = new Computer();
 
    @Override
    public void buildCpu() { computer.setCpu("Intel i7-13700K"); }
    @Override
    public void buildMemory() { computer.setMemory("16GB DDR5"); }
    @Override
    public void buildDisk() { computer.setDisk("1TB SSD"); }
    @Override
    public Computer getComputer() { return computer; }
}
 
// 戴尔电脑建造者
class DellBuilder implements IComputerBuilder {
    private Computer computer = new Computer();
 
    @Override
    public void buildCpu() { computer.setCpu("AMD Ryzen 7 7800X3D"); }
    @Override
    public void buildMemory() { computer.setMemory("32GB DDR5"); }
    @Override
    public void buildDisk() { computer.setDisk("2TB SSD"); }
    @Override
    public Computer getComputer() { return computer; }
}
4. 指挥者:Director

控制构建流程,按顺序调用建造者的方法。

class Director {
    // 接收抽象建造者,构建产品
    public Computer construct(IComputerBuilder builder) {
        builder.buildCpu();    // 第一步:装CPU
        builder.buildMemory(); // 第二步:装内存
        builder.buildDisk();   // 第三步:装硬盘
        return builder.getComputer(); // 返回成品
    }
}
5. 客户端调用

通过指挥者和具体建造者获取不同产品。

public class Client {
    public static void main(String[] args) {
        Director director = new Director();
  
        // 构建联想电脑
        IComputerBuilder lenovoBuilder = new LenovoBuilder();
        Computer lenovoPc = director.construct(lenovoBuilder);
        lenovoPc.showInfo(); // 输出:电脑配置:CPU=Intel i7-13700K, 内存=16GB DDR5, 硬盘=1TB SSD
  
        // 构建戴尔电脑
        IComputerBuilder dellBuilder = new DellBuilder();
        Computer dellPc = director.construct(dellBuilder);
        dellPc.showInfo(); // 输出:电脑配置:CPU=AMD Ryzen7 7800X3D, 内存=32GB DDR5, 硬盘=2TB SSD
    }
}

指挥者类Director有两个作用:一方面它隔离了客户端与创建过程;另一方面它控制了产品对象的创建过程,包括某个builderPartX()方法是否被调用以及多个builderPartX()方法调用的先后次序等。

指挥者类的深入讨论

省略director

客户端直接控制步骤

// Product类
class Computer {
    private String cpu;
    private String memory;
    private String disk;
 
    public void setCpu(String cpu) { this.cpu = cpu; }
    public void setMemory(String memory) { this.memory = memory; }
    public void setDisk(String disk) { this.disk = disk; }
 
    public void showInfo() {
        System.out.println("CPU: " + cpu + ", Memory: " + memory + ", Disk: " + disk);
    }
}
 
// 抽象Builder
interface IComputerBuilder {
    void buildCpu();
    void buildMemory();
    void buildDisk();
    Computer getComputer();
}
 
// 具体Builder(联想电脑)
class LenovoBuilder implements IComputerBuilder {
    private Computer computer = new Computer();
 
    @Override public void buildCpu() { computer.setCpu("Intel i7-13700K"); }
    @Override public void buildMemory() { computer.setMemory("16GB DDR5"); }
    @Override public void buildDisk() { computer.setDisk("1TB SSD"); }
    @Override public Computer getComputer() { return computer; }
}
 
// 客户端调用(手动控制步骤)
public class Client {
    public static void main(String[] args) {
        IComputerBuilder builder = new LenovoBuilder();
        // 客户端按顺序调用部件构建方法
        builder.buildCpu();
        builder.buildMemory();
        builder.buildDisk();
        Computer lenovoPc = builder.getComputer();
        lenovoPc.showInfo();
    }
}

Builder内部封装流程

在抽象Builder中增加 build()方法,封装默认步骤:

// 抽象Builder(新增build()方法)
interface IComputerBuilder {
    void buildCpu();
    void buildMemory();
    void buildDisk();
    Computer getComputer();
    // 内部封装流程
    default IComputerBuilder build() {
        buildCpu();
        buildMemory();
        buildDisk();
        return this;
    }
}
 
// 客户端调用(无需手动控制步骤)
public class Client {
    public static void main(String[] args) {
        Computer lenovoPc = new LenovoBuilder()
                                .build() // 调用内部封装的流程
                                .getComputer();
        lenovoPc.showInfo();
    }
}

引入钩子方法的建造者模式

钩子方法是抽象Builder中定义的布尔型方法,用于动态决定是否执行某个构建步骤,支持可选部件的构建,让流程更灵活。

1. 核心逻辑

  • 钩子方法:返回 boolean值,由具体Builder实现(如 isNeedGpu())。
  • 流程调整Director在构建时根据钩子结果,决定是否执行某个部件的构建步骤(如是否添加独立显卡)。

2. 代码示例

步骤1:扩展Product类(新增可选部件)

class Computer {
    private String cpu;
    private String memory;
    private String disk;
    private String gpu; // 可选部件(独立显卡)
 
    public void setCpu(String cpu) { this.cpu = cpu; }
    public void setMemory(String memory) { this.memory = memory; }
    public void setDisk(String disk) { this.disk = disk; }
    public void setGpu(String gpu) { this.gpu = gpu; }
 
    public void showInfo() {
        String info = "CPU: " + cpu + ", Memory: " + memory + ", Disk: " + disk;
        if (gpu != null) info += ", GPU: " + gpu;
        System.out.println(info);
    }
}

抽象Builder(增加钩子和可选部件方法)

interface IComputerBuilder {
    void buildCpu();
    void buildMemory();
    void buildDisk();
    void buildGpu(); // 可选部件构建方法
    boolean isNeedGpu(); // 钩子方法:是否需要GPU
    Computer getComputer();
}

具体Builder(实现钩子方法)

// 联想电脑(需要GPU)
class LenovoBuilder implements IComputerBuilder {
    private Computer computer = new Computer();
 
    @Override public void buildCpu() { computer.setCpu("Intel i7-13700K"); }
    @Override public void buildMemory() { computer.setMemory("16GB DDR5"); }
    @Override public void buildDisk() { computer.setDisk("1TB SSD"); }
    @Override public void buildGpu() { computer.setGpu("NVIDIA RTX 4070"); }
    @Override public boolean isNeedGpu() { return true; } // 钩子返回true
    @Override public Computer getComputer() { return computer; }
}
 
// 戴尔电脑(不需要GPU)
class DellBuilder implements IComputerBuilder {
    private Computer computer = new Computer();
 
    @Override public void buildCpu() { computer.setCpu("AMD Ryzen 7 7800X3D"); }
    @Override public void buildMemory() { computer.setMemory("32GB DDR5"); }
    @Override public void buildDisk() { computer.setDisk("2TB SSD"); }
    @Override public void buildGpu() {} // 空实现(无需GPU)
    @Override public boolean isNeedGpu() { return false; } // 钩子返回false
    @Override public Computer getComputer() { return computer; }
}

Director(结合钩子调整流程)

class Director {
    public Computer construct(IComputerBuilder builder) {
        builder.buildCpu();
        builder.buildMemory();
        builder.buildDisk();
        // 根据钩子判断是否构建GPU
        if (builder.isNeedGpu()) {
            builder.buildGpu();
        }
        return builder.getComputer();
    }
}
 
// 客户端调用
public class Client {
    public static void main(String[] args) {
        Director director = new Director();
        Computer lenovoPc = director.construct(new LenovoBuilder());
        Computer dellPc = director.construct(new DellBuilder());
  
        lenovoPc.showInfo(); // 包含GPU
        dellPc.showInfo(); // 无GPU
    }
}

建造者模式优缺点与适用环境

建造者模式的优点

  1. 封装性优异
    分离对象的“构建逻辑”与“表示形式”,用户无需了解产品内部的组装细节,只需通过指挥者即可获取成品。
    示例:用户购买定制电脑时,无需知道CPU如何安装、内存如何插卡,只需告诉商家配置需求(指挥者),商家(具体建造者)按流程组装即可。
  2. 精细控制构建过程
    允许分步、有序地构建产品,每个步骤均可定制化调整。
    示例:制作蛋糕时,可先选择蛋糕胚类型(戚风/海绵),再决定奶油口味(草莓/巧克力),最后添加装饰(水果/糖霜),每个步骤都能灵活修改。
  3. 扩展性强
    新增产品类型时,只需添加对应的具体建造者类,无需修改现有代码(符合开闭原则)。
    示例:汽车工厂原本生产轿车,若要新增SUV产品线,只需新增“SUV建造者”类,指挥者的构建流程(底盘→发动机→车身→内饰)保持不变。
  4. 复用性高
    相同的构建流程可复用在不同产品上,减少重复代码。
    示例:手机制造中,旗舰机和中端机的组装流程(主板→屏幕→电池→摄像头)一致,但部件规格不同,可复用同一指挥者逻辑。

建造者模式的缺点

  1. 产品差异过大时不适用
    若产品之间的核心部件或构建步骤差异显著,抽象建造者难以定义通用的构建接口,导致模式失效。
    示例:用建造者模式同时生产汽车和飞机,两者的部件(发动机类型、底盘结构)完全不同,无法通过统一的抽象建造者描述。
  2. 系统复杂度提升
    引入抽象建造者、具体建造者、指挥者等多个角色,增加了类的数量,使系统结构更复杂。
    示例:简单产品(如一杯咖啡)无需拆分多个步骤,使用建造者模式会显得“小题大做”,不如直接用工厂模式高效。
  3. 维护成本较高
    若产品内部结构发生变化(如新增部件),需修改所有具体建造者的相关方法,增加维护工作量。
    示例:手机新增无线充电模块后,所有手机建造者(旗舰机、中端机)都需添加“安装无线充电模块”的步骤。

建造者模式的适用环境

适用场景 详细说明
产品内部结构复杂 产品包含多个相互依赖的部件,需按特定顺序组装(如汽车、电脑)。
需生成不同表示的同类型产品 构建流程相同,但部件规格或组合方式不同(如不同配置的电脑、不同型号的手机)。
严格控制构建流程 要求产品必须按固定顺序生成,或需记录构建过程中的中间状态(如定制家具的分步制作)。
隔离创建与使用 希望隐藏产品的创建细节,避免用户直接操作内部部件(如软件框架中的复杂对象生成)。