文章

设计模式解密:建造者模式的终极指南(PHP/Go双实现)


一、什么是建造者模式?

建造者模式(Builder Pattern) 是一种创建型设计模式,用于分步骤构建复杂对象。其核心思想是将对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表现形式。建造者模式特别适用于具有多个可选参数或配置项的对象。

核心角色:

  1. 产品(Product):最终要构建的复杂对象

  2. 建造者接口(Builder):定义构建步骤的抽象方法

  3. 具体建造者(Concrete Builder):实现构建逻辑

  4. 指挥者(Director):控制构建流程(可选)

建造者模式结构图


二、适用场景

  • ✅ 需要创建包含多个组件的复杂对象

  • ✅ 对象的构建过程需要分步骤控制

  • ✅ 需要创建不同表现形式的同类对象

  • ✅ 避免构造函数参数过多(如超过4个参数)


三、PHP实现方案

1. 基础实现(带方法链)

class Computer {
    private $cpu;
    private $ram;
    private $storage;

    public function __construct() {
        $this->cpu = "Default CPU";
        $this->ram = "8GB";
        $this->storage = "256GB SSD";
    }

    public function setCpu(string $cpu): void {
        $this->cpu = $cpu;
    }

    public function setRam(string $ram): void {
        $this->ram = $ram;
    }

    public function setStorage(string $storage): void {
        $this->storage = $storage;
    }

    public function getSpecs(): string {
        return "CPU: {$this->cpu}, RAM: {$this->ram}, Storage: {$this->storage}";
    }
}

class ComputerBuilder {
    private $computer;

    public function __construct() {
        $this->computer = new Computer();
    }

    public function setCpu(string $cpu): self {
        $this->computer->setCpu($cpu);
        return $this;
    }

    public function setRam(string $ram): self {
        $this->computer->setRam($ram);
        return $this;
    }

    public function setStorage(string $storage): self {
        $this->computer->setStorage($storage);
        return $this;
    }

    public function build(): Computer {
        return $this->computer;
    }
}

// 使用示例
$builder = new ComputerBuilder();
$computer = $builder->setCpu("Intel i7")
                   ->setRam("32GB DDR4")
                   ->setStorage("1TB NVMe SSD")
                   ->build();
echo $computer->getSpecs(); // 输出:CPU: Intel i7, RAM: 32GB DDR4, Storage: 1TB NVMe SSD

2. 进阶实现(带指挥者)

interface Builder {
    public function reset(): void;
    public function setCpu(string $cpu): void;
    public function setRam(string $ram): void;
    public function setStorage(string $storage): void;
}

class GamingComputerBuilder implements Builder {
    private $computer;

    public function reset(): void {
        $this->computer = new Computer();
    }

    public function setCpu(string $cpu): void {
        $this->computer->setCpu($cpu);
    }

    public function setRam(string $ram): void {
        $this->computer->setRam($ram);
    }

    public function setStorage(string $storage): void {
        $this->computer->setStorage($storage);
    }

    public function getProduct(): Computer {
        return $this->computer;
    }
}

class Director {
    public function buildHighEndComputer(Builder $builder): Computer {
        $builder->reset();
        $builder->setCpu("AMD Ryzen 9");
        $builder->setRam("64GB DDR5");
        $builder->setStorage("2TB PCIe 4.0 SSD");
        return $builder->getProduct();
    }
}

// 使用示例
$director = new Director();
$builder = new GamingComputerBuilder();
$computer = $director->buildHighEndComputer($builder);
echo $computer->getSpecs(); // 输出:CPU: AMD Ryzen 9, RAM: 64GB DDR5, Storage: 2TB PCIe 4.0 SSD

四、Go实现方案

1. 基础实现(函数选项模式)

package main

import "fmt"

type Computer struct {
    CPU     string
    RAM     string
    Storage string
}

type ComputerBuilder struct {
    computer Computer
}

func NewComputerBuilder() *ComputerBuilder {
    return &ComputerBuilder{
        computer: Computer{
            CPU:     "Default CPU",
            RAM:     "8GB",
            Storage: "256GB SSD",
        },
    }
}

func (b *ComputerBuilder) SetCPU(cpu string) *ComputerBuilder {
    b.computer.CPU = cpu
    return b
}

func (b *ComputerBuilder) SetRAM(ram string) *ComputerBuilder {
    b.computer.RAM = ram
    return b
}

func (b *ComputerBuilder) SetStorage(storage string) *ComputerBuilder {
    b.computer.Storage = storage
    return b
}

func (b *ComputerBuilder) Build() Computer {
    return b.computer
}

// 使用示例
func main() {
    computer := NewComputerBuilder().
        SetCPU("Intel i7").
        SetRAM("32GB DDR4").
        SetStorage("1TB NVMe SSD").
        Build()
    fmt.Printf("%+v\n", computer) // 输出:{CPU:Intel i7 RAM:32GB DDR4 Storage:1TB NVMe SSD}
}

2. 进阶实现(带指挥者)

type Builder interface {
    Reset()
    SetCPU(string)
    SetRAM(string)
    SetStorage(string)
    GetComputer() Computer
}

type OfficeComputerBuilder struct {
    computer Computer
}

func (b *OfficeComputerBuilder) Reset() {
    b.computer = Computer{
        CPU:     "Intel i3",
        RAM:     "8GB",
        Storage: "512GB HDD",
    }
}

func (b *OfficeComputerBuilder) SetCPU(cpu string) {
    b.computer.CPU = cpu
}

func (b *OfficeComputerBuilder) SetRAM(ram string) {
    b.computer.RAM = ram
}

func (b *OfficeComputerBuilder) SetStorage(storage string) {
    b.computer.Storage = storage
}

func (b *OfficeComputerBuilder) GetComputer() Computer {
    return b.computer
}

type Director struct{}

func (d *Director) BuildStandardOfficeComputer(b Builder) Computer {
    b.Reset()
    b.SetCPU("Intel i5")
    b.SetRAM("16GB")
    b.SetStorage("512GB SSD")
    return b.GetComputer()
}

// 使用示例
func main() {
    director := Director{}
    builder := &OfficeComputerBuilder{}
    computer := director.BuildStandardOfficeComputer(builder)
    fmt.Printf("%+v\n", computer) // 输出:{CPU:Intel i5 RAM:16GB Storage:512GB SSD}
}

五、关键实现差异对比

特性

PHP

Go

方法链

通过return $this实现

返回接收者指针

接口实现

显式implements关键字

隐式接口实现

默认值设置

通过构造函数初始化

结构体字面量初始化

不可变对象

需要额外处理

可通过值类型实现

类型系统

强类型需显式声明

类型推断简化代码


六、模式优缺点分析

👍 优点:

  • 分步构建:支持复杂对象的逐步构造

  • 灵活扩展:可创建不同形式的产品

  • 封装细节:隐藏产品的内部表示

  • 参数控制:避免构造函数参数爆炸

👎 缺点:

  • 代码冗余:需要创建多个Builder类

  • 复杂度增加:简单对象可能过度设计

  • 性能损耗:多步骤构建带来额外开销


七、实际应用案例

1. HTTP请求构建

// PHP示例
$request = (new HttpRequestBuilder())
    ->setMethod('POST')
    ->setUrl('https://api.example.com')
    ->setHeaders(['Content-Type' => 'application/json'])
    ->setBody(json_encode(['key' => 'value']))
    ->build();

2. 数据库查询构造器

// Go示例
query := NewQueryBuilder().
    Select("name", "email").
    From("users").
    Where("age > ?", 18).
    OrderBy("created_at DESC").
    Build()

3. 游戏角色创建

$character = (new CharacterBuilder())
    ->setRace("Elf")
    ->setClass("Ranger")
    ->setEquipment("Bow", "Leather Armor")
    ->setSkills(["Stealth", "Archery"])
    ->build();

八、与工厂模式的区别

建造者模式

工厂模式

关注点

分步骤构建复杂对象

直接创建完整对象

适用场景

对象包含多个组件或配置项

创建单一类型对象

构建过程

显式控制每个步骤

隐藏创建细节

产品复杂度

高(多部件组合)

低到中等


九、总结

建造者模式是构建复杂对象的利器,通过分离构建过程与最终表示,它提供了极大的灵活性和可维护性。无论是PHP的方法链还是Go的函数选项模式,都能优雅地实现这一模式。当面对需要多参数配置的复杂对象时,建造者模式将成为您的首选方案。

在下一篇文章中,我们将探讨 原型模式 及其在对象复制中的应用。敬请期待!


下一篇预告:设计模式系列(五)——原型模式:高效复制的艺术

License:  CC BY 4.0