Builder Pattern

用建造者模式分步构建复杂对象

问题

什么是建造者模式?如何在 JavaScript 中实现?

解答

建造者模式将复杂对象的构建过程与其表示分离,使得同样的构建过程可以创建不同的表示。适用于需要创建包含多个可选参数的对象。

基础实现

class UserBuilder {
  constructor(name) {
    this.name = name;
  }

  setAge(age) {
    this.age = age;
    return this; // 返回 this 支持链式调用
  }

  setEmail(email) {
    this.email = email;
    return this;
  }

  setAddress(address) {
    this.address = address;
    return this;
  }

  build() {
    return {
      name: this.name,
      age: this.age,
      email: this.email,
      address: this.address,
    };
  }
}

// 使用
const user = new UserBuilder('张三')
  .setAge(25)
  .setEmail('zhangsan@example.com')
  .setAddress('北京')
  .build();

console.log(user);
// { name: '张三', age: 25, email: 'zhangsan@example.com', address: '北京' }

带 Director 的完整实现

// 产品类
class Computer {
  constructor() {
    this.parts = {};
  }

  setPart(name, value) {
    this.parts[name] = value;
  }

  show() {
    console.log('电脑配置:', this.parts);
  }
}

// 抽象建造者
class ComputerBuilder {
  constructor() {
    this.computer = new Computer();
  }

  buildCPU() {}
  buildMemory() {}
  buildStorage() {}

  getResult() {
    return this.computer;
  }
}

// 具体建造者 - 游戏电脑
class GamingComputerBuilder extends ComputerBuilder {
  buildCPU() {
    this.computer.setPart('CPU', 'Intel i9');
    return this;
  }

  buildMemory() {
    this.computer.setPart('Memory', '32GB DDR5');
    return this;
  }

  buildStorage() {
    this.computer.setPart('Storage', '2TB SSD');
    return this;
  }
}

// 具体建造者 - 办公电脑
class OfficeComputerBuilder extends ComputerBuilder {
  buildCPU() {
    this.computer.setPart('CPU', 'Intel i5');
    return this;
  }

  buildMemory() {
    this.computer.setPart('Memory', '16GB DDR4');
    return this;
  }

  buildStorage() {
    this.computer.setPart('Storage', '512GB SSD');
    return this;
  }
}

// 指挥者 - 控制构建流程
class Director {
  construct(builder) {
    return builder.buildCPU().buildMemory().buildStorage().getResult();
  }
}

// 使用
const director = new Director();

const gamingPC = director.construct(new GamingComputerBuilder());
gamingPC.show();
// 电脑配置: { CPU: 'Intel i9', Memory: '32GB DDR5', Storage: '2TB SSD' }

const officePC = director.construct(new OfficeComputerBuilder());
officePC.show();
// 电脑配置: { CPU: 'Intel i5', Memory: '16GB DDR4', Storage: '512GB SSD' }

实际应用:请求构建器

class RequestBuilder {
  constructor(url) {
    this.url = url;
    this.method = 'GET';
    this.headers = {};
    this.body = null;
    this.timeout = 5000;
  }

  setMethod(method) {
    this.method = method;
    return this;
  }

  setHeader(key, value) {
    this.headers[key] = value;
    return this;
  }

  setBody(body) {
    this.body = JSON.stringify(body);
    return this;
  }

  setTimeout(timeout) {
    this.timeout = timeout;
    return this;
  }

  async send() {
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), this.timeout);

    try {
      const response = await fetch(this.url, {
        method: this.method,
        headers: this.headers,
        body: this.body,
        signal: controller.signal,
      });
      clearTimeout(timeoutId);
      return response.json();
    } catch (error) {
      clearTimeout(timeoutId);
      throw error;
    }
  }
}

// 使用
const response = await new RequestBuilder('/api/users')
  .setMethod('POST')
  .setHeader('Content-Type', 'application/json')
  .setHeader('Authorization', 'Bearer token')
  .setBody({ name: '张三', age: 25 })
  .setTimeout(10000)
  .send();

关键点

  • 链式调用:每个设置方法返回 this,支持流畅的 API 设计
  • 分离构建与表示:相同的构建过程可以创建不同的对象
  • 可选参数处理:避免构造函数参数过多的问题
  • Director 可选:简单场景可省略,复杂场景用于封装固定构建流程
  • 适用场景:创建复杂对象、需要多步骤初始化、参数组合多样