1 什么是建造者模式?

建造者模式(Builder)是将一个复杂对象的构建层与其表示层相互分离,同样的构建过程可采用不同的表示。

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

同样作为创建型的设计模式,需要注意和工厂模式的区别,工厂虽然也是创建对象,但怎样创建无所谓,工厂模式关注的是创建的结果;而建造者模式不仅得到了结果,同时也参与了创建的具体过程,适合用来创建一个复杂的复合对象。

2 ES6中的建造者模式

下面我们来假设一个出版社的书籍后台录入系统的业务场景,书籍有四个必填信息,分别是:书名,作者,价格,分类;我们希望创建一个书籍对象返回给后端。下面我们来一步一步深入使用ES6的语法结合建造者模式创建对象。

  1. //书籍建造者类
  2. class BookBuilder {
  3. constructor() {
  4. this.name = '';
  5. this.author = '';
  6. this.price = 0;
  7. this.category = '';
  8. }
  9. withName(name) {
  10. this.name = name;
  11. return this;
  12. }
  13. withAuthor(author) {
  14. this.author = author;
  15. return this;
  16. }
  17. withPrice(price) {
  18. this.price = price;
  19. return this;
  20. }
  21. withCategory(category) {
  22. this.category = category;
  23. return this;
  24. }
  25. build() {
  26. return {
  27. name: this.name,
  28. author: this.author,
  29. prices: this.price,
  30. category: this.category
  31. }
  32. }
  33. }
  34. //调用建造者类
  35. const book = new BookBuilder()
  36. .withName("高效能人士的七个习惯")
  37. .withAuthor('史蒂芬·柯维')
  38. .withPrice(51)
  39. .withCategory('励志')
  40. .build();

上面就通过我BookBuilder这个创建者类的写法和调用方法,但是仅仅是一个4个属性的对象,我们使用了如此多的代码去创建,这远比直接在constructor传递参数创建对象要复杂得多。这是由于在创建的过程中,我们有太多的withxxxx方法。我们其实可以自动创建这类withxxxx方法以简化代码。

  1. //书籍建造者类
  2. class BookBuilder {
  3. constructor() {
  4. this.name = '';
  5. this.author = '';
  6. this.price = 0;
  7. this.category = '';
  8. Object.keys(this).forEach(key => {
  9. const withName = `with${key.substring(0, 1).toUpperCase()}${key.substring(1)}`;
  10. this[withName] = value => {
  11. this[key] = value;
  12. return this;
  13. }
  14. })
  15. }
  16. //调用建造者
  17. build() {
  18. const keysNoWithers = Object.keys(this).filter(key => typeof this[key] !== 'function');
  19. return keysNoWithers.reduce((returnValue, key) => {
  20. return {
  21. ...returnValue,
  22. [key]: this[key]
  23. }
  24. }, {})
  25. }
  26. }
  27. const book = new BookBuilder()
  28. .withName("高效能人士的七个习惯")
  29. .withAuthor('史蒂芬·柯维')
  30. .withPrice(51)
  31. .withCategory('励志')
  32. .build();

上面的BookBuilder这个类和第一个例子的效果一样,但是长度确减少不少,在有更多属性的时候,减少的代码量会更为明显。我们将所有的建造方法withxxxxconstructor调用时自动被创建,这里我们使用了一些ES6的新语法:Object.keys获取对象属性数组,...的合并对象的语法。

虽然该写法在阅读起来会比第一个方法难以理解,但是这样写法的真正作用在于,当我们需要许多的建造者类时,我们可以将上面自动创建withxxxbuild的代码提取为一个父类。在创建其他建造者类时继承该父类,这使得在创建多个建造者类时变得十分容易。

  1. //父类
  2. class BaseBuilder {
  3. init() {
  4. Object.keys(this).forEach(key => {
  5. const withName = `with${key.substring(0, 1).toUpperCase()}${key.substring(1)}`;
  6. this[withName] = value => {
  7. this[key] = value;
  8. return this;
  9. }
  10. })
  11. }
  12. build() {
  13. const keysNoWithers = Object.keys(this).filter(key => typeof this[key] !== 'function');
  14. return keysNoWithers.reduce((returnValue, key) => {
  15. return {
  16. ...returnValue,
  17. [key]: this[key]
  18. }
  19. }, {})
  20. }
  21. }
  22. //子类1: 书籍建造者类
  23. class BookBuilder extends BaseBuilder {
  24. constructor() {
  25. super();
  26. this.name = '';
  27. this.author = '';
  28. this.price = 0;
  29. this.category = '';
  30. super.init();
  31. }
  32. }
  33. //子类2: 印刷厂建造者类
  34. class printHouseBuilder extends BaseBuilder {
  35. constructor() {
  36. super();
  37. this.name = '';
  38. this.location = '';
  39. this.quality = '';
  40. super.init();
  41. }
  42. }
  43. //调用书籍建造者类
  44. const book = new BookBuilder()
  45. .withName("高效能人士的七个习惯")
  46. .withAuthor('史蒂芬·柯维')
  47. .withPrice(51)
  48. .withCategory('励志')
  49. .build();
  50. //调用印刷厂建造类
  51. const printHouse = new printHouseBuilder()
  52. .withName('新华印刷厂')
  53. .withLocation('北京海淀区')
  54. .withQuality('A')
  55. .build();

总结

在之前提到的几种工厂模式中,他们都有一个共同特点,就是对象的创建过程不得而知,我们在调用一个函数后返回了最终的结果对象。但是在创建者模式中我们关心的是对象的创建过程,我们通常将创建复杂对象的各个类模块化,在ES6中,我们采用importexport的语法可以很灵活的引用和导出这些模块进行我们的建造模式最终生成一个结果对象。

可以看出,建造者模式的使用有且只适合创建极为复杂的对象。在前端的实际业务中,在没有这类极为复杂的对象的创建时,还是应该直接使用对象字面或工厂模式等方式创建对象。


参考内容:
[1] An Exploration of JavaScript Builders —— Ryan Oglesby
[2] 《 JavaScript设计模式 》—— 张容铭

本文转载于:猿2048从ES6重新认识JavaScript设计模式(三): 建造者模式

从ES6重新认识JavaScript设计模式(三): 建造者模式的更多相关文章

  1. JavaScript设计模式之建造者模式

    一.建造者模式模式概念 建造者模式可以将一个复杂的对象的构建与其表示相分离,使得同样的构建过程可以创建不同的表示.也就是说如果我们用了建造者模式,那么用户就需要指定需要建造的类型就可以得到它们,而具体 ...

  2. 再起航,我的学习笔记之JavaScript设计模式08(建造者模式)

    我的学习笔记是根据我的学习情况来定期更新的,预计2-3天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧! 前几 ...

  3. JavaScript 设计模式之建造者模式

    一.建造者模式概念解读 1.建造者模式概念文字解读 建造者模式可以将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示.也就是说如果我们用了建造者模式,那么用户就需要指定需要建造的类 ...

  4. Java开发中常用的设计模式(三)---建造者模式

    一. 模式结构 建造者模式主要包含四个角色: Product:产品角色. Builder:抽象建造者.它声明为创建一个Product对象的各个部件指定的抽象接口. ConcreteBuilder:具体 ...

  5. php设计模式三-----建造者模式

    1.简介 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示. 主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子 ...

  6. 从ES6重新认识JavaScript设计模式: 装饰器模式

    1 什么是装饰器模式 向一个现有的对象添加新的功能,同时又不改变其结构的设计模式被称为装饰器模式(Decorator Pattern),它是作为现有的类的一个包装(Wrapper). 可以将装饰器理解 ...

  7. C++设计模式之建造者模式(三)

    4.引入钩子方法的建造者模式 建造者模式除了逐步构建一个复杂产品对象外.还能够通过Director类来更加精细地控制产品的创建过程.比如添加一类称之为钩子方法(HookMethod)的特殊方法来控制是 ...

  8. Java设计模式之建造者模式(Builder)

    前言: 最近一直在学习okHttp,也对其做了一些整理,okHttp和Retrofit结合大大加速我们的开发效率,源码里面采用了很多设计模式,今天我们来学习一下其中的设计模式之一建造者模式. 建造者模 ...

  9. C#设计模式(5)——建造者模式(Builder Pattern)

    一.引言 在软件系统中,有时需要创建一个复杂对象,并且这个复杂对象由其各部分子对象通过一定的步骤组合而成.例如一个采购系统中,如果需要采购员去采购一批电脑时,在这个实际需求中,电脑就是一个复杂的对象, ...

随机推荐

  1. 民间流转的pytest项目结构设计

    创建上图的pytest项目结构,只需要一条命令即可: tep startproject demo 前提是安装tep0.9.8版本: pip install tep==0.9.8 示例代码单独放在了sa ...

  2. 9.resultMap元素

    resultMap 是 MyBatis 中最复杂的元素,主要用于解决实体类属性名与数据库表中字段名不一致的情况,可以将查询结果映射成实体对象.下面我们先从最简单的功能开始介绍. 现有的 MyBatis ...

  3. GoLang设计模式21 - 装饰模式

    装饰器模式是一种结构型设计模式.通过装饰器模式可以为一个对象添加额外的功能而不需对其作出调整. 还是通过具体的案例来了解装饰器模式:假设我们开了一家披萨店,现在店里主营两款披萨: 素食狂披萨(Vegg ...

  4. JS类型判断&原型链

    JS类型检测主要有四种 1.typeof Obj 2.L instanceof R 3.Object.prototype.toString.call/apply(); 4.Obj.constructo ...

  5. C++高并发场景下读多写少的优化方案

    概述 一谈到高并发的优化方案,往往能想到模块水平拆分.数据库读写分离.分库分表,加缓存.加mq等,这些都是从系统架构上解决.单模块作为系统的组成单元,其性能好坏也能很大的影响整体性能,本文从单模块下读 ...

  6. ansible 一 简介和部署

    一.Ansible的介绍 Ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点.实现了批量系统配置 ...

  7. dedecms 5.7 任意前台用户修改漏洞

    一. 启动环境 1.双击运行桌面phpstudy.exe软件 2.点击启动按钮,启动服务器环境 二.代码审计 1.双击启动桌面Seay源代码审计系统软件 2.点击新建项目按钮,弹出对画框中选择(C:\ ...

  8. 【Vulnhub】LazySysAdmin

    下载链接 https://download.vulnhub.com/lazysysadmin/Lazysysadmin.zip 运行环境 Virtualbox Vnware Workstation p ...

  9. Redis 系统学习目录

    Redis 系统学习目录 1.redis是什么2.redis的作者何许人也3.谁在使用redis4.学会安装redis5.学会启动redis6.使用redis客户端7.redis数据结构 – 简介8. ...

  10. java反射和动态代理实现与原理详细分析

    关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式    代理模式是常用的java设计模式, ...