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();
相关推荐
st紫月9 分钟前
用vue和go实现登录加密
前端·vue.js·golang
岁岁岁平安20 分钟前
Vue3学习(组合式API——计算属性computed详解)
前端·javascript·vue.js·学习·computed·计算属性
HWL56791 小时前
Express项目解决跨域问题
前端·后端·中间件·node.js·express
刺客-Andy1 小时前
React 第三十九节 React Router 中的 unstable_usePrompt Hook的详细用法及案例
前端·javascript·react.js
Go_going_1 小时前
【js基础笔记] - 包含es6 类的使用
前端·javascript·笔记
浩~~2 小时前
HTML5 浮动(Float)详解
前端·html·html5
AI大模型顾潇3 小时前
[特殊字符] 本地大模型编程实战(29):用大语言模型LLM查询图数据库NEO4J(2)
前端·数据库·人工智能·语言模型·自然语言处理·prompt·neo4j
九月TTS3 小时前
TTS-Web-Vue系列:Vue3实现内嵌iframe文档显示功能
前端·javascript·vue.js
爱编程的小学究3 小时前
【node】如何把包发布到npm上
前端·npm·node.js
我爱加班、、3 小时前
Chrome安装最新vue-devtool插件
javascript·vue.js·chrome·vue-devtool