23种设计模式之建造者模式

特性

虽然也是为了创建对象,但是相比于工厂模式,该模式更关注创建过程及细节。

基础术语

构建层

定义与作用

构建层是指 负责对象创建过程部分 的代码。

它定义了创建对象的步骤和方法,但不直接指定对象的具体表示形式。

构建层所拥有的角色

  1. 抽象构建者(Abstract Builder) :定义创建对象各个部件的接口。
  2. 具体构建者(Concrete Builder) :实现抽象构建者接口,逐步构建复杂对象的各个部件。
  3. 指挥者(Director) :使用构建者来创建对象,通常不依赖于具体构建者的实现,而是通过抽象构建者接口与构建者交互。

表示层

表示层是指对象的最终表示形式或结构。它定义了对象的内部状态和行为,但不直接参与对象的创建过程。表示层通常是一个独立的类,用于存储对象的属性和方法。

优点

  1. 分离构建过程与表示:将复杂的构建过程与最终的表示分离,使得可以使用不同的构建过程形成不同的最终表示。
  2. 逐步构建对象:允许逐步构建复杂对象,便于添加新的构建步骤。
  3. 代码复用:通过构建器类复用构建逻辑,减少重复代码。
  4. 灵活性:可以轻松地创建不同的对象表示,只需实现不同的构建器类。

缺点

  1. 增加代码复杂度:引入了额外的类,使得代码结构变得更加复杂。
  2. 可能产生过多的类:如果需要创建多种不同的对象表示,可能会产生过多的构建器类。

定义

将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示。

可以用不同组合或顺序建造出不同意义的对象,通常使用者并不需要知道建造的细节,通常使用链式调用 来进行建造过程,最后调用build方法来生成最终对象。

应用场景

  1. 构建复杂的对象或界面组件
  2. 在需要分步骤创建对象时。
  3. 当需要为同一对象创建多种不同的表示时。

如何实现

  1. 实现表示层 类:主要用于描述最终产物的各种行为。
  2. 构建抽象建造者:主要用于确定构建功能模块的类型,并且创建表示层类的实例。

通常用一个有方法及属性但无具体实现的父类来表示。在ts可以使用接口类来代替父类。

对于一些与建造无关的方法可以将实现放置在父类,剩余的应该下放到子类实现。

会在构造函数中进行表示层类的实例的创建及存储。

  1. 构建具体建造者:抽象建造者的子类,相当于对抽象建造者描述的创建过程中各个功能模块进行具体实现。

每个功能模块应该返回 this ,方便后续链式调用

  1. 构建指挥者:主要集成了进行各种类型的对象构建的方法。

该步骤可以省略,直接合并至步骤 5

  1. 客户端使用:用于构建整体对象并使用,完成业务需求的实现

示例

动态表单生成器

需求说明

构建一个用户注册表单,包含基础信息、地址信息、偏好设置等模块,且不同场景下模块组合可能变化。

构建步骤

  1. 产出表示层类:表单配置对象,用于进行表单的各种行为的承载
typescript 复制代码
class FormConfig {
  constructor() {
    this.fields = [];
  }
  addField(type, label, required = false) {
    this.fields.push({ type, label, required });
  }
  render() {
    return this.fields.map(field => <>表单项</>);
  }
}
  1. 构建抽象建造者
javascript 复制代码
class FormBuilder {
  constructor() {
    this.form = new FormConfig();
  }
  buildBasicInfo() {}
  buildAddress() {}
  buildPreferences() {}
  getForm() {
    return this.form;
  }
}
  1. 构建具体建造者
kotlin 复制代码
class RegistrationFormBuilder extends FormBuilder {
  buildBasicInfo() {
    this.form.addField('text', '用户名', true);
    this.form.addField('email', '邮箱', true);
    return this; // 支持链式调用
  }

  buildAddress() {
    this.form.addField('text', '街道');
    this.form.addField('text', '城市');
    return this;
  }

  buildPreferences() {
    this.form.addField('checkbox', '订阅新闻');
    return this;
  }
}
  1. 创建指挥者
kotlin 复制代码
class FormDirector {
  constructor(builder) {
    this.builder = builder;
  }

  buildFullForm() {
    return this.builder
      .buildBasicInfo()
      .buildAddress()
      .buildPreferences()
      .getForm();
  }

  buildMinimalForm() {
    return this.builder
      .buildBasicInfo()
      .getForm();
  }
}
  1. 客户端使用
ini 复制代码
// 创建建造者
const builder = new RegistrationFormBuilder();

// 方式1:直接使用建造者(灵活自定步骤)
const customForm = builder
  .buildBasicInfo()
  .buildPreferences()
  .getForm();


// 方式2:通过指挥者(标准化流程)
const director = new FormDirector(builder);
const fullForm = director.buildFullForm();
相关推荐
Restart-AHTCM21 分钟前
前端核心框架vue之(路由篇3/5)
前端·javascript·vue.js
段振轩31 分钟前
Docker nginx容器部署前端项目。
前端·nginx·docker
让时光到此为止。1 小时前
vue的首屏优化是怎么做的
前端·javascript·vue.js
San302 小时前
JavaScript 流程控制与数组操作全解析:从条件判断到数据高效处理
javascript·面试·代码规范
温宇飞2 小时前
CSS 中如何处理空白字符
前端
dengzhenyue2 小时前
矩形碰撞检测
开发语言·前端·javascript
llq_3502 小时前
为什么 npm view yarn version 显示 1.22.22?
前端
aesthetician2 小时前
ReactFlow:构建交互式节点流程图的完全指南
前端·流程图·react
neo_dowithless2 小时前
多语言维护太痛苦?我自研了一个翻译自动化 CLI 工具
前端·ai编程
小徐_23332 小时前
老乡鸡也开源?我用 Trae SOLO 做了个像老乡鸡那样做饭小程序!
前端·trae