JS设计模式之“分即是合” - 建造者模式

news2024/12/24 20:53:21

image.png

引言

当我们在进行软件编程时,常常会遇到需要创建复杂对象的情况。这些对象可能有多个属性,属性之间存在依赖关系,或需要按照特定的骤来创建。在这种情况下,使用建造者模式Builder Pattern)可以提供一种活的方式来构建对象,避免对象构建过程的复杂性。

“分即是合” - 将对象的创建过程与其表示相互分离,但允许我们连续地构建对象逐步设置其属性,然后获取最终的构建结果

一. 什么是建造者模式

建造者模式(Builder Pattern)是一种创建型设计模式,旨在将对象的创建过程与其表示相互分离。它允许我们连续地构建对象逐步设置其属性,然后获取最终的构建结果。使用建造者模式,我们可以按照自己的需求构建对象,而不必关心对象的创建过程和内部细节。

fileOf7174.png

建造者模式通常包含以下几个角色:

  1. Director(导演):负责定义构建过程的顺序和逻辑,控制对象的创建过程。

  2. Builder(建造者):负责实际构建复杂对象的接口,定义了创建对象的每个步骤。

  3. ConcreteBuilder(具体建造者):实现 Builder 接口,实际进行对象的构建。

  4. Product(产品):表示最终构建完成的对象。

二. 深入建造者模式的神奇之处

案例场景一

fileOf7174.png

骑士对象

让我们通过一个简单的例子来说明建造者模式。假设我们正在开发一个游戏,需要构建一种特殊类型的角色:骑士。骑士有许多属性,包括名字等级武器盔甲等。为了构建骑士对象,我们可以使用建造者模式。

首先,我们定义一个角色类,用于表示骑士对象:

class Knight {
  constructor(name, level, weapon, armor) {
    this.name = name;
    this.level = level;
    this.weapon = weapon;
    this.armor = armor;
  }

  toString() {
    return `${this.name}, ${this.level}, weapon: ${this.weapon}, armor: ${this.armor}`;
  }
}

然后,我们定义一个骑士建造者类,用于逐步构建骑士对象:

class KnightBuilder {
  constructor() {
    this.name = null;
    this.level = null;
    this.weapon = null;
    this.armor = null;
  }
  // 名称
  setName(name) {
    this.name = name;
    return this;
  }
  // 等级
  setLevel(level) {
    this.level = level;
    return this;
  }
  // 武器
  setWeapon(weapon) {
    this.weapon = weapon;
    return this;
  }
  // 盔甲
  setArmor(armor) {
    this.armor = armor;
    return this;
  }
  // 构造骑士
  build() {
    return new Knight(this.name, this.level, this.weapon, this.armor);
  }
}

在这个例子,我们定义了一个KnightBuilder类它包含了与骑士对象相关的各种属性我们可以使用该建造者类逐步设置这些属性,终通过调用 build 方法来获取建完成的骑士对象。

接下来,让我们使用建造者模式来构建一个骑士对象:

const knight = new KnightBuilder()
  .setName("Arthur")
  .setLevel(10)
  .setWeapon("Excalibur")
  .setArmor("Plate")
  .build();

console.log(knight.toString());

在这个例子中,我们首先创建了一个 KnightBuilder 实例,并逐步设置了骑士对象的各个属性。最后,通过调用 build 方法,我们获取到了构建完成的骑士对象并打印出来。输出结果为:

Arthur, Level 10, weapon: Excalibur, armor: Plate

总结:

正如我们所看到的,通过建造者模式,我们可以在不污染对象类的情况下,方便地构建出具有各种属性的骑士对象。

案例场景二

fileOf7174.png

汽车对象

让我们继续通过一个汽车示例来加深对建造者式的使用。假设我们正在构建一个汽车对象,并且汽车具有一些复杂的属性。下面是一个简化的汽车建造者实现:

class Car {
  constructor() {
    this.brand = null;
    this.color = null;
    this.engine = null;
  }
}

class CarBuilder {
  constructor() {
    this.car = new Car();
  }
  // 品牌
  setBrand(brand) {
    this.car.brand = brand;
    return this;
  }
  // 颜色
  setColor(color) {
    this.car.color = color;
    return this;
  }
  // 引擎
  setEngine(engine) {
    this.car.engine = engine;
    return this;
  }

  build() {
    return this.car;
  }
}

// 创建汽车对象示例
const car = new CarBuilder()
  .setBrand("Tesla")
  .setColor("Red")
  .setEngine("Electric")
  .build();

console.log(car);

在上面的示例中,我们有一个 Car 类表示汽车对象,包含了 brandcolorengine 等属性。然后,我们创建了一个 CarBuilder 类,用于逐步构建 Car 对象。CarBuilder 类中的各方法用于设置 Car 对象各个属性,并且每个方法都返回 CarBuilder 实例,以便可以进行链式调用。最后,通过调用 build 方法来返回最终 Car 对象。

以上的例子均展示了建造者模式的基本用法,我们可以根据实际情况,将建造者模式扩展到更复杂的情况,例如构建具有更多属性和复杂构建过程的对象。

三. 为什么要使用建造者模式

通过以上的实例我们可以总结使用建造者模式的优点:

  1. 灵活性高:建造者模式允许逐步构建复杂对象,并且可以根据需求自由选择和配置对象的属性,而不需要关心对象的创建过程和内部细节。

  2. 代码可读性好:通过将对象的构建过程封装在建造者类中,代码更加清晰直观。建造者模式提供了一种结构化的方式来创建对象,使得代码易于理解和维护

  3. 创建不可变对象:通过将对象的属性设置为私有,并提供相应的 getter 方法,可以确保对象在创建后不会被修改,增加对象的安全性和封装性。

  4. 代码复用性高:可以将复杂对象构建的逻辑封装在建造者类中,以便在同一场景下复用。

当然,任何一件事物并不是只有优点没有缺点,当然建造者模式也是有一定的缺点的。

  1. 增加代码量:引入建造者模式会增加一些额外的类和方法,这可能导致代码量的增加。有时候,如果只需要简单的对象,使用建造者模式可能会过于繁琐。

  2. 对象构建过程不够灵活:建造者模式在创建对象时要按照一定的顺序和一系列步骤。这可能会限制构建过程的灵活性,不够适应某些特殊情况。

  3. 可能存在建造者类过多:当对象有很多属性时,可能需要创建多个建造者类来构建对象。这可能会导致建造者类的增加,给代码的维护和理解带来一定的复杂性。

总结:

建造者模式适用于构建复杂的场景,特别当对象有多个属性、属性之有依赖关系或需要按照特定的顺序构建时。某些情况下,对象比较简单,使用建者模式可能会显得过于复杂和冗余。因此使用建造者模式需要权衡利弊,选择适合的设计模式。

四. 建造者模式和工厂模式的对比

JavaScript中的建造者模式和工厂模式在创建对象上有一些不同之处,下面是总结的一些对比。

对比方式

对比方式建造者模式工厂模式
目的和使用场景主要用于创建具有复杂属性和构建过程的对象。它可以逐步构建对象,并提供灵活的方法来设置对象的各个属性。适用于构建过程复杂,有多个步骤和可变参数的对象。主要用于根据不同的条件或参数创建不同类型的对象。它提供统一的接口来创建对象,只需要知道该接口而不用心具体的实现细节。
使用方式通过连续调用建造者类的方法来逐步构建对象最后通过获取构建结果的方法来获取最终的对象。通过调用工厂类的方法,传入相应参数或条件,工厂类根据传入的参数条件来创建相应的对象,并返回给客户端。
灵活性允许在构建对象时自由配置属性,并且可以选择性地属性。根据设置特定的属性,可以不设置某些属性适用于对象属性较多且有可选项的场景。工厂模式的创建逻辑相对固定,只需要传入相应的参数或条件,工厂类根据这些参数或条件来创建相应的对象。适用于对象创建不涉及复杂的逻辑判断,只是根据条件返回不同类型的对象。
代码复用可以将构建对象的逻辑封装在建造者中,可以不同的场景下复用相同的构建逻辑。将对象创建的逻辑封装在工厂中,可以根据不同的或参数创建不同的,从而实现代码的复用。

总结

综上所述,工厂模式和建造者模式都是用于创建对象的设计模式,他们在使用方式和灵活性上有一定的不同之处:

  • 工厂模式适用于创建不同类型的对象,根据条件或参数返回相应的对象,工厂模式主要关注对象的创建过程。

  • 建造者模式适用于创建具有复杂属性和构建过程的对象,建造者模式主要关注对象属性的设置和构建流程的控制。

小结

通过本文,我们了解到了JavaScript建造者模式的详细使用方式,最后我们在总结一下什么情况下我们会考虑使用建造者模式:

  1. 对象拥有复杂的属性:如果要创建的对象具有很多属性,而且这些属性之间存在一定的依赖关系或可选项,使用建造者模式可以提供更灵活的方式来构建对象,避免创建过程的复杂性。

  2. 构建过程具有多个步骤:如果对象的构建过程包含多个步骤,并且这些步骤可能因为不同的需求或条件而变化,使用建造者模式可以将构建过程分解为多个方法,并在其中逐步构建对象。

  3. 需要创建不可变对象:建造者模式可以通过将对象的属性设置为私有,并提供相应的 getter 方法,从而创建不可变对象。这样做可以保证对象的属性在创建后不会被修改,提高了对象的安全性和封装性。

  4. 需要代码的可读性和可维护性:使用建造者模式,可以将对象的构建过程、属性设置的逻辑都封装在建造者类中,这样可以使得代码更加清晰直观,易于理解和维护。

  5. 需要复用相同的构建逻辑:如果有多个场景需要使用相同的构建逻辑创建对象,可以将该构建逻辑抽象为一个建造者类,以便在不同的场景下复用同一份代码。

建造者模式适合用于构建具有复杂属性、多步骤构建过程、可配置性要求高的对象,并且需要提高代码的可读性和可维护性的情况下。通过使用建造者模式,可以简化对象的构建过程,有效地管理对象的属性和属性设置的逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2096873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

搭建IPsec VPN隧道解决PLC设备与主控上位机无法使用公网IP进行通信的问题

问题描述 按照初设规定,每个工程点位都要安装一条具有独立公网IP的光纤专线,供该点位的视频监控设备、水质监测设备及PLC设备与外界进行通信。而在项目开发前期并没有意识到,组态软件(上位机)无法通过公网IP地址连接PLC,导致在交…

【网络原理】Udp 的报文结构,保姆式教学,快速入门

本篇会加入个人的所谓鱼式疯言 ❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言 而是理解过并总结出来通俗易懂的大白话, 小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的. 🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人…

Tomcat 配置SSL

1、生成SSL证书&#xff1b; 2、配置Tomcat文件&#xff1b; <Connector port"8080" protocol"HTTP/1.1"SSLEnabled"true"keystoreFile"D:/hk.jks"keystorePass"123456"clientAuth"false"sslProtocol"TL…

js字符串格式的数字比较大小

1300>37 为什么是false? 在 JavaScript 中&#xff0c;当比较两个字符串时&#xff0c;比较是基于字典顺序&#xff08;也就是按字符的 Unicode 编码值进行比较&#xff09;的&#xff0c;而不是数字的实际大小。因此&#xff0c;1300 > 37 的结果是 false&#xff0c;…

Halcon提取边缘线段lines_gauss 算子

Halcon提取边缘线段lines_gauss 算子 edges_color_sub_pix和edges_sub_pix两个算子使用边缘滤波器进行边缘检测。还有一个常用的算子lines_gauss算子&#xff0c;也可以用于提取边缘线段&#xff0c;它的鲁棒性非常好&#xff0c;提取出的线段类型是亚像素精度的XLD轮廓。其原…

【GD32】RT-Thread实时操作系统移植(GD32F470ZGT6)

1. 简介 最近几年可以发现国产的实时操作系统越来越受欢迎了&#xff0c;本篇要移植的就是当中的翘楚——RT-Thread。 RT-Thread诞生于2006年&#xff0c;是国内以开源中立、社区化发展起来的一款高可靠实时操作系统 &#xff0c;由睿赛德科技负责开发维护和运营 。并且在上一年…

机器学习面试:请介绍下LR的损失函数?

在机器学习中&#xff0c;逻辑回归&#xff08;Logistic Regression, LR&#xff09;是一种广泛使用的分类算法&#xff0c;尤其适用于二分类问题。逻辑回归的损失函数主要是用来衡量模型预测值与真实值之间的差距。以下是对逻辑回归损失函数的详细介绍&#xff1a; 1. 逻辑回…

【千帆AppBuilder】使用Python调用基于官方的API创建图片故事的应用,一起体验下全代码模式下是怎样的效果

欢迎来到《小5讲堂》 这是《千帆》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景基本信息名称简介角色指令 能力扩展组件对话开场白推荐问 模型选…

Rust到底值不值得学,之二

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust到底值不值得学&#xff0c;之一 -CSDN博客 1.2.2 引用和借用 如果每次都发生所有权的转移&#xff0c;程序的编写就会变得异…

LVGL 控件之图表部件(lv_chart)

目录 一、图表1、组成2、类型3、显示数据3.1 lv_chart_set_ext_y_array/lv_chart_set_ext_x_array3.2 lv_chart_set_next_value3.3 lv_chart_set_all_value3.4 lv_chart_set_value_by_id3.5 在数组中手动设置 4、设置数据点数量5、辅助功能5.1 垂直范围5.2 分隔线5.3 设置默认起…

Mathematica如何进行公式推导和使用

目录 一、内容描述 二、如何打出公式[2] 三、具体操作 四、参考文献 一、内容描述 在Mathematica中通过几个简单命令可以将一大串的三角函数进行分解及简化&#xff0c;大大节省了推导时间&#xff0c;并保证了推导的正确性。 二、如何打出公式[2] 具体操作&#xff1a…

VastBase——VPatch版本控制

一、准备工作 1.概述 VPatch是用于Vastbase版本控制的工具。可以实现在单机环境下的升级和回退操作&#xff0c;具体功能如下&#xff1a; 升级环境检查&#xff0c;补丁冲突检查等。 PSU、PSR、OOP补丁的升级、回退、升级或回退失败时的还原。 升级过程中记录相关日志和步…

华为OD机试真题 - 来自异国的客人(Python/JS/C/C++ 2024 D卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试真题&#xff08;Python/JS/C/C&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加入华为OD刷题交流群&#xff0c;…

使用老毛桃的一些坑

个性设置不要去点 三种模式的区别 ISO模式&#xff1a;直接U盘成为某个系统的启动盘 本地模式&#xff1a;相当于硬盘中植入一个PE系统&#xff0c;与后续的windows系统&#xff0c;一起组成双系统 普通模式&#xff1a;PE系统在U盘中&#xff0c;这样ISO可以是多种不同的系…

98.SAP MII功能详解(12)Workbench-Transaction Logic(For Next Loop)

目录 1.Logic->For Next Loop 2.演示 配置对象 配置连接 for循环的整体演示 1.Logic->For Next Loop 此操作用于在预定义的次数内执行任务。每次迭代都会执行直接跟随For Next循环操作的所有操作&#xff0c;直到达到To限制。 若要在达到To属性限制之前停止&…

我用GPT对RAG技术的学习和探索

思维导图 下图是我的学习和探索过程&#xff0c;红点表示已研究&#xff0c;黄点表示待研究 目录 思维导图RAG技术概述RAG 的关键优点应用场景 如何了解RAG技术的原理和应用1. **基础理论学习**2. **实战演练**3. **学习资源利用**4. **保持学习的连贯性**5. **多角度理解**6. …

SpringBoot配置返回数据不存在null

一、引言 最近在做项目中遇到一个神奇的问题&#xff0c;在测试返回银行三级数据的时候有的项目中返回的数据中把null值的数据返回了&#xff0c;而有的时候就不存在null值数据&#xff0c;如下所示&#xff1a; 存在null值情况 不含null值情况 但是我们可以看一下返回的VO的…

AG32 MCU如何指定一段RAM可以重启或复位不丢失数据

AG32 MCU如何指定一段RAM可以重启或复位不丢失数据? 目前还没这样的功能。 建议可以试下&#xff1a; 把系统ram设置成120K&#xff0c;最后的8K只能自己访问。 这样重启时&#xff0c;系统不会自动擦除最后的8K。可能是可以的。 备份寄存器大概有几十字节可以用。但是这个需…

2024最新comfyui保姆级教程来啦!comfyui工作流搭建看这一篇就够了!

前言 一、SD主流 UI Stable Diffusion&#xff08;SD&#xff09;因为其开源特性&#xff0c;有着较高的受欢迎程度&#xff0c;并且基于SD的开源社区及教程、插件等&#xff0c;都是所有工具里最多的。基于SD&#xff0c;有不同的操作界面&#xff0c;可以理解为一个工具的不…

基于zigbee的广告牌安全监测系统设计与实现(论文+源码)

1.系统方案 本次基于Zigbee的广告牌安全监测系统&#xff0c;使用Zigbee组网&#xff0c;一共具有2块板子&#xff0c;其中1块作为协调器&#xff0c;另1块作为终端。首先由协调器构建Zigbee网络&#xff0c;终端连上协调器网络后&#xff0c;每隔1秒钟采集一次传感器数据并通…