JS如何实现建造者模式?建造者步骤详解与代码示例

来源:JS教程作者:李修然头衔:网络博主
导读:本期聚焦于李修然创作的《JS如何实现建造者模式?建造者步骤详解与代码示例》,敬请观看详情。建造者模式是一种把复杂对象创建过程拆分成多个步骤的创建型设计模式。当对象的属性很多、构造参数容易搞混,或者对象需要分阶段组装时,用它比直接new一个对象清晰得多。本文用JavaScript完整演示建造者模式的核心结构:指挥者、抽象建造者与具体建造者,通过一个表单生成器的实战案例,一步步展示如何定义buildPart方法、如何用链式调用简化对象组装、如何在Director中封装固定的建造流程。文章还会对比建造者模式与工厂模式的区别,分析各自适用的场景,并给出一份可直接运行的完整代码,帮助你真正掌握这种模式的落地写法。

平时写JavaScript的时候,如果遇到一个对象有十几个属性,构造函数的参数列表往往会长到没法看。调用的时候不仅要记住参数顺序,还容易传错位置,排查起来相当费劲。建造者模式(Builder Pattern)就是为了解决这类问题而生的:它把一个复杂对象的构建过程拆成一个个独立的步骤,每一步只负责装配一部分内容,最后统一产出完整对象。这篇文章会从模式结构讲起,配合可运行的代码,把JS里实现建造者模式的完整步骤说清楚。

JS如何实现建造者模式?建造者步骤详解与代码示例

一、建造者模式的核心结构与角色分工

建造者模式属于创建型设计模式,它的核心思想是将对象的构建过程与表示分离。换句话说,同样的构建步骤,可以产出不同形态的对象。整个模式通常由四个角色组成:产品(Product)、抽象建造者(Builder)、具体建造者(ConcreteBuilder)和指挥者(Director)。

产品角色就是最终要生成的复杂对象,比如一个包含多个区块的页面配置、一份带样式和校验规则的表单。抽象建造者定义了构建产品各个部件的接口,例如buildHeader()buildBody()这类方法。具体建造者则实现这些接口,不同的实现方式能产出不同风格的产品。指挥者负责调用建造者的方法,按固定顺序完成组装,它不关心具体细节,只负责流程编排。

这四个角色协作的流程是:客户端先创建一个具体建造者,把它交给指挥者;指挥者按既定顺序调用建造者的各个build方法;最后从建造者手中取出装配完成的产品。这种分工带来的最大好处是,产品的内部组装逻辑被封装起来了,客户端只需要说"我要什么",不需要知道"怎么拼"。

二、用JS一步步实现一个表单生成器

下面通过一个表单生成器的例子来演示完整实现步骤。假设我们要生成一个包含标题、输入框列表和提交按钮的表单配置对象。先定义产品类,它承载最终的数据结构:

// 产品角色:表单配置
class FormData {
  constructor() {
    this.title = '';
    this.fields = [];
    this.button = null;
  }
  show() {
    console.log('表单标题:' + this.title);
    this.fields.forEach(f => console.log('字段:' + f.label));
    if (this.button) {
      console.log('提交按钮:' + this.button.text);
    }
  }
}

接着定义抽象建造者。由于JavaScript没有严格的接口概念,通常用一个基类声明方法,未实现的直接抛出错误,起到约束作用:

// 抽象建造者
class FormBuilder {
  buildTitle(title) { throw new Error('必须实现 buildTitle'); }
  buildField(field) { throw new Error('必须实现 buildField'); }
  buildButton(text) { throw new Error('必须实现 buildButton'); }
  getResult() { throw new Error('必须实现 getResult'); }
}

// 具体建造者:普通风格表单
class NormalFormBuilder extends FormBuilder {
  constructor() {
    super();
    this.form = new FormData();
  }
  buildTitle(title) {
    this.form.title = title;
    return this; // 返回this支持链式调用
  }
  buildField(field) {
    this.form.fields.push(field);
    return this;
  }
  buildButton(text) {
    this.form.button = { text: text, type: 'submit' };
    return this;
  }
  getResult() {
    return this.form;
  }
}

注意每个build方法都返回this,这是实现链式调用的关键。最后是指挥者,它封装了一套固定的组装流程:

// 指挥者:封装固定建造流程
class FormDirector {
  constructor(builder) {
    this.builder = builder;
  }
  construct(config) {
    this.builder.buildTitle(config.title);
    config.fields.forEach(field => this.builder.buildField(field));
    this.builder.buildButton(config.buttonText);
    return this.builder.getResult();
  }
}

// 客户端调用
const builder = new NormalFormBuilder();
const director = new FormDirector(builder);
const form = director.construct({
  title: '用户注册',
  fields: [
    { label: '用户名', type: 'text' },
    { label: '密码', type: 'password' }
  ],
  buttonText: '立即注册'
});
form.show();

运行后就能得到一个装配完整的表单配置对象。如果之后需要一个带红色主题、字段自动加必填校验的版本,只需要再写一个RedStyleFormBuilder继承抽象建造者,指挥者的流程完全不用改动,这就是模式带来的扩展性。

三、链式调用简化版:去掉Director的写法

在前端开发中,很多时候并不需要严格的四角色结构,可以省略指挥者,直接让客户端通过链式调用组装对象。这种简化版在各类组件库和工具库里非常常见,比如jQuery的链式API就是类似思路。

// 简化的链式建造者
class QueryBuilder {
  constructor(table) {
    this.table = table;
    this.conditions = [];
    this.orderField = null;
  }
  where(cond) {
    this.conditions.push(cond);
    return this;
  }
  orderBy(field) {
    this.orderField = field;
    return this;
  }
  build() {
    let sql = 'SELECT * FROM ' + this.table;
    if (this.conditions.length) {
      sql += ' WHERE ' + this.conditions.join(' AND ');
    }
    if (this.orderField) {
      sql += ' ORDER BY ' + this.orderField;
    }
    return sql + ';';
  }
}

// 使用
const sql = new QueryBuilder('users')
  .where('age > 18')
  .where('status = 1')
  .orderBy('created_at')
  .build();
console.log(sql);
// 输出:SELECT * FROM users WHERE age > 18 AND status = 1 ORDER BY created_at;

这种写法的可读性非常好,每一步做了什么一目了然。它的代价是流程控制权交给了客户端,步骤的调用顺序不再受统一约束。如果步骤之间存在强依赖(比如必须先buildTitle才能buildField),还是建议保留Director角色,在construct方法里固定顺序,避免调用方乱序导致半成品对象。

另外提醒一点,链式建造者通常要实现一个build()getResult()作为终点方法,它的职责是做最终校验并返回产品。如果发现必填项缺失,在这里抛出异常比让残缺对象流到下游更安全。

四、建造者模式与工厂模式的区别及选型建议

不少人会把建造者模式和工厂模式混为一谈,虽然两者都是创建型模式,但关注点完全不同。工厂模式关心的是"创建什么",根据入参返回不同类型的对象,一次调用就出结果;建造者模式关心的是"怎么创建",强调分步骤组装,调用方可以参与到构建过程中间。

可以从三个维度判断该用哪个。第一看对象复杂度:只有几个属性、一次构造就能完成的,用工厂或直接字面量即可;属性多、结构分层、需要部分组装的,用建造者。第二看是否需要控制流程:如果不同场景下组装顺序不同,或者要复用同一套组装流程,Director能发挥价值。第三看参数可读性:当构造函数参数超过四五个、且有多个同类型参数时,链式建造者的方法名天然带语义,比一长串位置参数可靠得多。

还要注意一个常见误区:不是所有链式调用都算建造者模式。判断的关键在于对象是否被拆成了多个部件逐步装配,以及是否存在一个明确的最终产出动作。像Array的map().filter()链只是普通的方法链,每次都返回新数组,并不涉及同一个复杂对象的分步构建。

总结一下,在JS中实现建造者模式的步骤可以归纳为:定义产品类承载最终数据,编写建造者类并为每个部件提供build方法,让方法返回this以支持链式调用,需要流程约束时引入Director封装组装顺序,最后提供getResult或build方法输出成品。掌握这套思路后,无论是构建复杂配置对象、拼接查询语句,还是设计组件库的初始化API,都能用上这种优雅的组织方式。

建造者模式JavaScript设计模式Builder模式修改时间:2026-09-07 21:18:41

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260907/52452.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。