95、23种设计模式之建造者模式(4/23)

建造者模式(Builder Pattern)是23种经典设计模式中的创建型模式之一,其核心思想是将复杂对象的构建过程与其表示分离,使得同样的构建流程可以生成不同结构或配置的对象。以下从定义、结构、应用场景、优缺点及代码示例展开分析:

一、模式定义

建造者模式通过分步构建复杂对象,将对象的构造逻辑(如部件创建、组装顺序)封装在独立的建造者类中,客户端只需指定建造者类型即可获得最终产品,无需了解内部细节。

类比:如同在餐厅点餐,顾客只需选择套餐类型(如A套餐、B套餐),厨师(建造者)会按固定流程准备食材(部件)并组合成完整餐品(产品)。

二、模式结构

建造者模式通常包含以下角色:

1.产品(Product)

复杂对象,由多个部件组成(如汽车由引擎、轮胎、车身等部件构成)。

2.抽象建造者(Builder)

定义创建产品各部件的抽象方法(如buildEngine()、buildWheel()),并提供获取最终产品的方法(如getVehicle())。

3.具体建造者(ConcreteBuilder)

实现抽象建造者接口,具体定义部件的创建和组装逻辑,返回不同配置的产品实例。

4.指挥者(Director)

封装构建流程,调用建造者的方法按固定顺序组装产品(可选角色,客户端也可直接调用建造者)。

三、应用场景

1.复杂对象构造

对象由多个部件构成,且部件创建步骤复杂(如计算机组装需选择CPU、内存、硬盘等)。

2.相同流程不同表示

构建过程稳定,但部件组合方式多样(如汽车可组装为SUV、跑车等不同型号)。

3.隔离构造与使用

客户端无需关心对象内部细节,只需关注最终产品(如通过StringBuilder.append()逐步构建字符串,最后调用toString()获取结果)。

4.可选部件处理

对象包含可选属性,避免使用冗长的构造函数或Setter方法(如通过链式调用设置对象属性)。

四、优缺点分析

1.优点

(1)解耦构建与表示:客户端无需知道产品内部结构,只需指定建造者类型。

(2)扩展性强:新增具体建造者不影响现有代码,符合开闭原则。

(3)控制构建细节:可灵活调整部件创建顺序或条件(如根据配置选择引擎类型)。

2.缺点

(1)类数量增加:需定义抽象建造者、具体建造者等额外类,系统复杂度上升。

(2)维护成本高:若产品内部结构变化,所有建造者均需修改。

(3)适用范围有限:仅适用于部件数量多、构造过程复杂的对象。

五、代码示例(C#)

以下是一个 完整的 C# 建造者模式示例,包含 产品类、抽象建造者、具体建造者、指挥者 和 客户端调用,并支持 链式调用:

csharp 复制代码
using System;

// 1. 产品类(Computer)
public class Computer
{
    public string CPU { get; set; }
    public string RAM { get; set; }
    public string Storage { get; set; }
    public string GPU { get; set; }
    public bool HasKeyboard { get; set; }
    public bool HasMouse { get; set; }

    public override string ToString()
    {
        return $@"
Computer Configuration:
    CPU: {CPU}
    RAM: {RAM}
    Storage: {Storage}
    GPU: {GPU}
    Keyboard: {(HasKeyboard ? "Included" : "Not Included")}
    Mouse: {(HasMouse ? "Included" : "Not Included")}";
    }
}

// 2. 抽象建造者(IComputerBuilder)
public interface IComputerBuilder
{
    IComputerBuilder SetCPU(string cpu);
    IComputerBuilder SetRAM(string ram);
    IComputerBuilder SetStorage(string storage);
    IComputerBuilder SetGPU(string gpu);
    IComputerBuilder IncludeKeyboard(bool include);
    IComputerBuilder IncludeMouse(bool include);
    Computer Build();
}

// 3. 具体建造者(GamingComputerBuilder)
public class GamingComputerBuilder : IComputerBuilder
{
    private Computer _computer = new Computer();

    public IComputerBuilder SetCPU(string cpu) { _computer.CPU = cpu; return this; }
    public IComputerBuilder SetRAM(string ram) { _computer.RAM = ram; return this; }
    public IComputerBuilder SetStorage(string storage) { _computer.Storage = storage; return this; }
    public IComputerBuilder SetGPU(string gpu) { _computer.GPU = gpu; return this; }
    public IComputerBuilder IncludeKeyboard(bool include) { _computer.HasKeyboard = include; return this; }
    public IComputerBuilder IncludeMouse(bool include) { _computer.HasMouse = include; return this; }
    public Computer Build() { return _computer; }
}

// 4. 指挥者(ComputerDirector)
public class ComputerDirector
{
    public Computer BuildGamingPC(IComputerBuilder builder)
    {
        return builder
            .SetCPU("AMD Ryzen 9 5900X")
            .SetRAM("64GB DDR4")
            .SetStorage("2TB NVMe SSD")
            .SetGPU("NVIDIA RTX 3080 Ti")
            .IncludeKeyboard(true)
            .IncludeMouse(true)
            .Build();
    }

    public Computer BuildOfficePC(IComputerBuilder builder)
    {
        return builder
            .SetCPU("Intel i5")
            .SetRAM("16GB DDR4")
            .SetStorage("512GB SSD")
            .SetGPU("Integrated Graphics")
            .IncludeKeyboard(false)
            .IncludeMouse(false)
            .Build();
    }
}

// 5. 客户端代码
class Program
{
    static void Main()
    {
        // 使用指挥者构建标准配置
        var director = new ComputerDirector();
        var builder = new GamingComputerBuilder();

        Computer gamingPC = director.BuildGamingPC(builder);
        Computer officePC = director.BuildOfficePC(builder);

        Console.WriteLine("=== Standard Gaming PC ===");
        Console.WriteLine(gamingPC);

        Console.WriteLine("\n=== Standard Office PC ===");
        Console.WriteLine(officePC);

        // 直接链式调用自定义配置
        Computer customPC = new GamingComputerBuilder()
            .SetCPU("Apple M1 Ultra")
            .SetRAM("128GB")
            .SetStorage("8TB SSD")
            .SetGPU("AMD Radeon Pro")
            .IncludeKeyboard(true)
            .Build();

        Console.WriteLine("\n=== Custom PC ===");
        Console.WriteLine(customPC);
    }
}

关键设计点

1.链式调用

通过返回 IComputerBuilder 实现流畅接口(如 SetCPU().SetRAM().Build())。

2.指挥者

封装固定构建流程(如 BuildGamingPC()),适合重复性构造。

3.灵活性

既可通过指挥者快速构建标准配置,也可直接链式调用自定义配置。

适用于需要 分步构建复杂对象 且 支持多种配置 的场景(如电脑、汽车、报表生成等)。

六、模式变体与实际应用

1.链式调用

通过方法返回this实现链式调用(如new Computer.Builder().cpu("i9").ram("32GB").build()),简化客户端代码。

2.与工厂模式结合

工厂模式关注对象创建,建造者模式关注对象构造过程,两者可结合使用(如先通过工厂获取建造者,再调用建造者组装产品)。

3.JDK中的应用

StringBuilder、StringBuffer均采用建造者模式,通过append()方法逐步构建字符串,最后调用toString()获取结果。

七、总结

建造者模式适用于构造复杂对象的场景,通过解耦构建过程与产品表示,提升代码的灵活性和可维护性。其核心优势在于分步构建和精细控制,但需权衡类数量增加带来的复杂度。在实际开发中,可根据对象复杂度选择是否引入指挥者角色,或直接使用链式调用的简化形式。