Skip to content

构建者模式详解:概念、实现与应用

引言

构建者模式是一种创建型设计模式,它能将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。构建者模式关注的是如何分步骤创建复杂的对象,允许用户只通过指定复杂对象的类型和内容就可以构建它们,而不需要知道内部的具体构建细节。

什么是构建者模式?

构建者模式是一种创建型设计模式,它使你能够分步骤创建复杂对象。该模式允许你使用相同的创建代码生成不同类型和形式的对象。

核心思想

构建者模式的核心思想是:

  1. 分离构建与表示:将一个复杂对象的构建与其表示分离
  2. 分步骤构建:将构建过程分解为多个步骤
  3. 统一构建过程:使用相同的构建过程创建不同的表示

为什么需要构建者模式?

在许多情况下,我们需要创建复杂的对象,这些对象的创建过程可能涉及多个步骤:

1. 复杂对象构造

当对象的构造过程比较复杂时:

  • 对象包含多个组成部分
  • 构造步骤可能根据情况变化
  • 需要创建不同的对象表示

2. 对象创建的灵活性

当需要灵活控制对象创建过程时:

  • 可以省略某些步骤
  • 可以改变步骤的执行顺序
  • 可以复用相同的构建过程

3. 避免重叠构造函数

当类有多个构造函数参数时:

  • 避免出现多个重叠的构造函数
  • 提供更清晰的对象创建方式
  • 支持参数的逐步设置

构建者模式的基本实现

让我们从一个简单的构建者模式实现开始:

javascript
// 产品类
class Product {
  constructor() {
    this.parts = [];
  }
  
  addPart(part) {
    this.parts.push(part);
  }
  
  listParts() {
    return `产品部件: ${this.parts.join(', ')}`;
  }
}

// 构建者接口
class Builder {
  producePartA() {
    throw new Error('必须实现 producePartA 方法');
  }
  
  producePartB() {
    throw new Error('必须实现 producePartB 方法');
  }
  
  producePartC() {
    throw new Error('必须实现 producePartC 方法');
  }
  
  getProduct() {
    throw new Error('必须实现 getProduct 方法');
  }
}

// 具体构建者
class ConcreteBuilder extends Builder {
  constructor() {
    super();
    this.reset();
  }
  
  reset() {
    this.product = new Product();
  }
  
  producePartA() {
    this.product.addPart('PartA');
    return this;
  }
  
  producePartB() {
    this.product.addPart('PartB');
    return this;
  }
  
  producePartC() {
    this.product.addPart('PartC');
    return this;
  }
  
  getProduct() {
    const result = this.product;
    this.reset();
    return result;
  }
}

// 指挥者
class Director {
  setBuilder(builder) {
    this.builder = builder;
  }
  
  buildMinimalProduct() {
    this.builder.producePartA();
  }
  
  buildFullProduct() {
    this.builder.producePartA()
               .producePartB()
               .producePartC();
  }
  
  buildCustomProduct() {
    this.builder.producePartA()
               .producePartC();
  }
}

// 客户端代码
function clientCode() {
  const builder = new ConcreteBuilder();
  const director = new Director();
  director.setBuilder(builder);
  
  console.log('基本产品:');
  director.buildMinimalProduct();
  const product1 = builder.getProduct();
  console.log(product1.listParts());
  
  console.log('完整产品:');
  director.buildFullProduct();
  const product2 = builder.getProduct();
  console.log(product2.listParts());
  
  console.log('自定义产品:');
  director.buildCustomProduct();
  const product3 = builder.getProduct();
  console.log(product3.listParts());
  
  // 不使用指挥者
  console.log('自定义构建:');
  builder.producePartA()
         .producePartB();
  const product4 = builder.getProduct();
  console.log(product4.listParts());
}

clientCode();

实现要点分析

  1. 产品类:定义要构建的复杂对象
  2. 构建者接口:定义构建步骤的接口
  3. 具体构建者:实现构建步骤,构造和装配产品的各个部件
  4. 指挥者:构造一个使用构建者接口的对象
  5. 客户端:创建 Director 对象,并用它所想要的 Builder 对象进行配置

构建者模式的实际应用场景

1. 复杂表单构建器

在前端开发中,构建者模式非常适合用于构建复杂的表单:

javascript
// 表单产品类
class Form {
  constructor() {
    this.fields = [];
    this.validationRules = [];
    this.onSubmitHandler = null;
  }
  
  addField(field) {
    this.fields.push(field);
  }
  
  addValidationRule(rule) {
    this.validationRules.push(rule);
  }
  
  setOnSubmitHandler(handler) {
    this.onSubmitHandler = handler;
  }
  
  render() {
    let html = '<form>';
    
    this.fields.forEach(field => {
      html += `<div class="form-field">${field.render()}</div>`;
    });
    
    html += '<button type="submit">提交</button>';
    html += '</form>';
    
    return html;
  }
  
  validate() {
    const errors = [];
    this.validationRules.forEach(rule => {
      const error = rule.validate();
      if (error) {
        errors.push(error);
      }
    });
    return errors;
  }
}

// 表单字段基类
class FormField {
  constructor(name, label) {
    this.name = name;
    this.label = label;
  }
  
  render() {
    throw new Error('必须实现 render 方法');
  }
}

// 文本输入字段
class TextInput extends FormField {
  render() {
    return `<label>${this.label}</label><input type="text" name="${this.name}" />`;
  }
}

// 邮箱输入字段
class EmailInput extends FormField {
  render() {
    return `<label>${this.label}</label><input type="email" name="${this.name}" />`;
  }
}

// 下拉选择字段
class SelectField extends FormField {
  constructor(name, label, options) {
    super(name, label);
    this.options = options;
  }
  
  render() {
    let html = `<label>${this.label}</label><select name="${this.name}">`;
    this.options.forEach(option => {
      html += `<option value="${option.value}">${option.text}</option>`;
    });
    html += '</select>';
    return html;
  }
}

// 验证规则基类
class ValidationRule {
  validate() {
    throw new Error('必须实现 validate 方法');
  }
}

// 必填验证规则
class RequiredRule extends ValidationRule {
  constructor(fieldName, message = '此字段为必填项') {
    super();
    this.fieldName = fieldName;
    this.message = message;
  }
  
  validate() {
    // 简化的验证逻辑
    const value = document.querySelector(`[name="${this.fieldName}"]`)?.value;
    if (!value) {
      return this.message;
    }
    return null;
  }
}

// 邮箱验证规则
class EmailRule extends ValidationRule {
  constructor(fieldName, message = '请输入有效的邮箱地址') {
    super();
    this.fieldName = fieldName;
    this.message = message;
  }
  
  validate() {
    const value = document.querySelector(`[name="${this.fieldName}"]`)?.value;
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (value && !emailRegex.test(value)) {
      return this.message;
    }
    return null;
  }
}

// 表单构建者接口
class FormBuilder {
  addField(field) {
    throw new Error('必须实现 addField 方法');
  }
  
  addValidationRule(rule) {
    throw new Error('必须实现 addValidationRule 方法');
  }
  
  setOnSubmitHandler(handler) {
    throw new Error('必须实现 setOnSubmitHandler 方法');
  }
  
  build() {
    throw new Error('必须实现 build 方法');
  }
}

// 具体表单构建者
class ConcreteFormBuilder extends FormBuilder {
  constructor() {
    super();
    this.reset();
  }
  
  reset() {
    this.form = new Form();
  }
  
  addField(field) {
    this.form.addField(field);
    return this;
  }
  
  addValidationRule(rule) {
    this.form.addValidationRule(rule);
    return this;
  }
  
  setOnSubmitHandler(handler) {
    this.form.setOnSubmitHandler(handler);
    return this;
  }
  
  build() {
    const result = this.form;
    this.reset();
    return result;
  }
}

// 使用示例
function createUserRegistrationForm() {
  const builder = new ConcreteFormBuilder();
  
  const form = builder
    .addField(new TextInput('username', '用户名'))
    .addField(new EmailInput('email', '邮箱'))
    .addField(new SelectField('gender', '性别', [
      { value: 'male', text: '男' },
      { value: 'female', text: '女' }
    ]))
    .addValidationRule(new RequiredRule('username'))
    .addValidationRule(new RequiredRule('email'))
    .addValidationRule(new EmailRule('email'))
    .setOnSubmitHandler((data) => {
      console.log('提交用户注册数据:', data);
    })
    .build();
  
  return form;
}

function createContactForm() {
  const builder = new ConcreteFormBuilder();
  
  const form = builder
    .addField(new TextInput('name', '姓名'))
    .addField(new EmailInput('email', '邮箱'))
    .addField(new TextInput('subject', '主题'))
    .addField(new TextInput('message', '消息'))
    .addValidationRule(new RequiredRule('name'))
    .addValidationRule(new RequiredRule('email'))
    .addValidationRule(new EmailRule('email'))
    .addValidationRule(new RequiredRule('subject'))
    .addValidationRule(new RequiredRule('message'))
    .setOnSubmitHandler((data) => {
      console.log('提交联系表单数据:', data);
    })
    .build();
  
  return form;
}

// 使用示例
const registrationForm = createUserRegistrationForm();
console.log('用户注册表单 HTML:');
console.log(registrationForm.render());

const contactForm = createContactForm();
console.log('联系表单 HTML:');
console.log(contactForm.render());

2. SQL 查询构建器

在数据库操作中,构建者模式非常适合用于构建复杂的 SQL 查询:

javascript
// SQL 查询产品类
class SQLQuery {
  constructor() {
    this.selectFields = [];
    this.fromTable = '';
    this.joins = [];
    this.whereConditions = [];
    this.groupByFields = [];
    this.havingConditions = [];
    this.orderByFields = [];
    this.limitValue = null;
    this.offsetValue = null;
  }
  
  toString() {
    let query = 'SELECT ';
    
    // SELECT 子句
    if (this.selectFields.length > 0) {
      query += this.selectFields.join(', ');
    } else {
      query += '*';
    }
    
    // FROM 子句
    if (this.fromTable) {
      query += ` FROM ${this.fromTable}`;
    }
    
    // JOIN 子句
    if (this.joins.length > 0) {
      query += ' ' + this.joins.join(' ');
    }
    
    // WHERE 子句
    if (this.whereConditions.length > 0) {
      query += ` WHERE ${this.whereConditions.join(' AND ')}`;
    }
    
    // GROUP BY 子句
    if (this.groupByFields.length > 0) {
      query += ` GROUP BY ${this.groupByFields.join(', ')}`;
    }
    
    // HAVING 子句
    if (this.havingConditions.length > 0) {
      query += ` HAVING ${this.havingConditions.join(' AND ')}`;
    }
    
    // ORDER BY 子句
    if (this.orderByFields.length > 0) {
      query += ` ORDER BY ${this.orderByFields.join(', ')}`;
    }
    
    // LIMIT 和 OFFSET 子句
    if (this.limitValue !== null) {
      query += ` LIMIT ${this.limitValue}`;
    }
    
    if (this.offsetValue !== null) {
      query += ` OFFSET ${this.offsetValue}`;
    }
    
    return query;
  }
}

// SQL 查询构建者接口
class SQLQueryBuilder {
  select(fields) {
    throw new Error('必须实现 select 方法');
  }
  
  from(table) {
    throw new Error('必须实现 from 方法');
  }
  
  join(table, condition) {
    throw new Error('必须实现 join 方法');
  }
  
  leftJoin(table, condition) {
    throw new Error('必须实现 leftJoin 方法');
  }
  
  where(condition) {
    throw new Error('必须实现 where 方法');
  }
  
  groupBy(fields) {
    throw new Error('必须实现 groupBy 方法');
  }
  
  having(condition) {
    throw new Error('必须实现 having 方法');
  }
  
  orderBy(fields) {
    throw new Error('必须实现 orderBy 方法');
  }
  
  limit(value) {
    throw new Error('必须实现 limit 方法');
  }
  
  offset(value) {
    throw new Error('必须实现 offset 方法');
  }
  
  build() {
    throw new Error('必须实现 build 方法');
  }
}

// 具体 SQL 查询构建者
class ConcreteSQLQueryBuilder extends SQLQueryBuilder {
  constructor() {
    super();
    this.reset();
  }
  
  reset() {
    this.query = new SQLQuery();
  }
  
  select(fields) {
    if (typeof fields === 'string') {
      this.query.selectFields.push(fields);
    } else if (Array.isArray(fields)) {
      this.query.selectFields.push(...fields);
    }
    return this;
  }
  
  from(table) {
    this.query.fromTable = table;
    return this;
  }
  
  join(table, condition) {
    this.query.joins.push(`JOIN ${table} ON ${condition}`);
    return this;
  }
  
  leftJoin(table, condition) {
    this.query.joins.push(`LEFT JOIN ${table} ON ${condition}`);
    return this;
  }
  
  where(condition) {
    this.query.whereConditions.push(condition);
    return this;
  }
  
  groupBy(fields) {
    if (typeof fields === 'string') {
      this.query.groupByFields.push(fields);
    } else if (Array.isArray(fields)) {
      this.query.groupByFields.push(...fields);
    }
    return this;
  }
  
  having(condition) {
    this.query.havingConditions.push(condition);
    return this;
  }
  
  orderBy(fields) {
    if (typeof fields === 'string') {
      this.query.orderByFields.push(fields);
    } else if (Array.isArray(fields)) {
      this.query.orderByFields.push(...fields);
    }
    return this;
  }
  
  limit(value) {
    this.query.limitValue = value;
    return this;
  }
  
  offset(value) {
    this.query.offsetValue = value;
    return this;
  }
  
  build() {
    const result = this.query;
    this.reset();
    return result;
  }
}

// 使用示例
function buildUserQuery() {
  const builder = new ConcreteSQLQueryBuilder();
  
  const query = builder
    .select(['u.id', 'u.name', 'u.email', 'p.title'])
    .from('users u')
    .leftJoin('posts p', 'u.id = p.user_id')
    .where('u.active = 1')
    .groupBy(['u.id', 'u.name', 'u.email'])
    .having('COUNT(p.id) > 0')
    .orderBy('u.name ASC')
    .limit(10)
    .offset(0)
    .build();
  
  return query;
}

function buildSimpleUserQuery() {
  const builder = new ConcreteSQLQueryBuilder();
  
  const query = builder
    .select('*')
    .from('users')
    .where('age > 18')
    .orderBy('created_at DESC')
    .build();
  
  return query;
}

// 使用示例
const userQuery = buildUserQuery();
console.log('复杂用户查询:');
console.log(userQuery.toString());

const simpleUserQuery = buildSimpleUserQuery();
console.log('简单用户查询:');
console.log(simpleUserQuery.toString());

3. HTTP 请求构建器

在网络请求中,构建者模式也非常有用:

javascript
// HTTP 请求产品类
class HTTPRequest {
  constructor() {
    this.method = 'GET';
    this.url = '';
    this.headers = {};
    this.body = null;
    this.timeout = 5000;
    this.credentials = 'same-origin';
  }
  
  setMethod(method) {
    this.method = method.toUpperCase();
    return this;
  }
  
  setURL(url) {
    this.url = url;
    return this;
  }
  
  addHeader(key, value) {
    this.headers[key] = value;
    return this;
  }
  
  setBody(body) {
    this.body = body;
    return this;
  }
  
  setTimeout(timeout) {
    this.timeout = timeout;
    return this;
  }
  
  setCredentials(credentials) {
    this.credentials = credentials;
    return this;
  }
  
  async send() {
    const options = {
      method: this.method,
      headers: this.headers,
      credentials: this.credentials,
      timeout: this.timeout
    };
    
    if (this.body) {
      options.body = this.body;
    }
    
    try {
      const response = await fetch(this.url, options);
      return response;
    } catch (error) {
      throw new Error(`请求失败: ${error.message}`);
    }
  }
  
  toObject() {
    return {
      method: this.method,
      url: this.url,
      headers: { ...this.headers },
      body: this.body,
      timeout: this.timeout,
      credentials: this.credentials
    };
  }
}

// HTTP 请求构建者接口
class HTTPRequestBuilder {
  get(url) {
    throw new Error('必须实现 get 方法');
  }
  
  post(url) {
    throw new Error('必须实现 post 方法');
  }
  
  put(url) {
    throw new Error('必须实现 put 方法');
  }
  
  delete(url) {
    throw new Error('必须实现 delete 方法');
  }
  
  addHeader(key, value) {
    throw new Error('必须实现 addHeader 方法');
  }
  
  setBody(body) {
    throw new Error('必须实现 setBody 方法');
  }
  
  setTimeout(timeout) {
    throw new Error('必须实现 setTimeout 方法');
  }
  
  setCredentials(credentials) {
    throw new Error('必须实现 setCredentials 方法');
  }
  
  build() {
    throw new Error('必须实现 build 方法');
  }
}

// 具体 HTTP 请求构建者
class ConcreteHTTPRequestBuilder extends HTTPRequestBuilder {
  constructor() {
    super();
    this.reset();
  }
  
  reset() {
    this.request = new HTTPRequest();
  }
  
  get(url) {
    this.request.setMethod('GET').setURL(url);
    return this;
  }
  
  post(url) {
    this.request.setMethod('POST').setURL(url);
    return this;
  }
  
  put(url) {
    this.request.setMethod('PUT').setURL(url);
    return this;
  }
  
  delete(url) {
    this.request.setMethod('DELETE').setURL(url);
    return this;
  }
  
  addHeader(key, value) {
    this.request.addHeader(key, value);
    return this;
  }
  
  setBody(body) {
    this.request.setBody(body);
    return this;
  }
  
  setTimeout(timeout) {
    this.request.setTimeout(timeout);
    return this;
  }
  
  setCredentials(credentials) {
    this.request.setCredentials(credentials);
    return this;
  }
  
  build() {
    const result = this.request;
    this.reset();
    return result;
  }
}

// 使用示例
async function buildAndSendUserRequest() {
  const builder = new ConcreteHTTPRequestBuilder();
  
  const request = builder
    .get('https://api.example.com/users')
    .addHeader('Authorization', 'Bearer token123')
    .addHeader('Content-Type', 'application/json')
    .setTimeout(10000)
    .setCredentials('include')
    .build();
  
  console.log('请求配置:', request.toObject());
  
  try {
    const response = await request.send();
    console.log('响应状态:', response.status);
    return response;
  } catch (error) {
    console.error('请求失败:', error.message);
  }
}

async function buildAndSendCreateUserRequest() {
  const builder = new ConcreteHTTPRequestBuilder();
  
  const userData = {
    name: '张三',
    email: 'zhangsan@example.com',
    age: 30
  };
  
  const request = builder
    .post('https://api.example.com/users')
    .addHeader('Authorization', 'Bearer token123')
    .addHeader('Content-Type', 'application/json')
    .setBody(JSON.stringify(userData))
    .setTimeout(10000)
    .build();
  
  console.log('请求配置:', request.toObject());
  
  try {
    const response = await request.send();
    console.log('响应状态:', response.status);
    return response;
  } catch (error) {
    console.error('请求失败:', error.message);
  }
}

// 使用示例
buildAndSendUserRequest();
buildAndSendCreateUserRequest();

构建者模式与工厂模式的对比

构建者模式

javascript
// 构建者模式关注分步骤构建复杂对象
class Builder {
  step1() { /* 构建步骤1 */ }
  step2() { /* 构建步骤2 */ }
  step3() { /* 构建步骤3 */ }
  getResult() { /* 返回构建结果 */ }
}

工厂模式

javascript
// 工厂模式关注创建对象
class Factory {
  createProduct(type) {
    // 根据类型创建不同产品
  }
}

对比总结

特性构建者模式工厂模式
关注点分步骤构建复杂对象创建对象
复杂度较高,适用于复杂对象较低,适用于简单对象
构建过程可以控制构建步骤一步创建完成
适用场景对象构建过程复杂对象创建相对简单

构建者模式的优缺点

优点

  1. 分步骤构建:可以分步骤创建复杂对象
  2. 控制构建过程:可以控制构建过程,决定是否执行某个步骤
  3. 复用代码:相同的构建代码可以创建不同的表示
  4. 单一职责原则:将复杂对象的构建代码从其他代码中分离出来

缺点

  1. 类数量增加:需要创建多个类来实现该模式
  2. 系统复杂度增加:整体结构变得更加复杂
  3. 客户端必须知道构建细节:如果不用指挥者,客户端需要知道构建的细节

总结

构建者模式是一种创建型设计模式,它将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示。构建者模式特别适用于创建具有复杂内部结构的对象。

通过本章的学习,我们了解了:

  1. 构建者模式的基本概念和核心思想
  2. 构建者模式的实现方式
  3. 构建者模式在实际开发中的应用场景(复杂表单构建器、SQL查询构建器、HTTP请求构建器)
  4. 构建者模式与其他创建型模式的对比
  5. 构建者模式的优缺点

构建者模式在现代软件开发中应用广泛,特别是在需要创建复杂对象的场景中,它可以很好地支持系统的灵活性和可维护性。

在下一章中,我们将继续探讨其他创建型模式,如原型模式。