资讯专栏INFORMATION COLUMN

从ES6重新认识JavaScript设计模式(三): 建造者模式

hatlonely / 3079人阅读

摘要:书籍建造者类调用建造者高效能人士的七个习惯史蒂芬柯维励志上面的这个类和第一个例子的效果一样,但是长度确减少不少,在有更多属性的时候,减少的代码量会更为明显。参考内容设计模式张容铭

1 什么是建造者模式?

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

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

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

2 ES6中的建造者模式

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

//书籍建造者类
class BookBuilder {
  constructor() {
    this.name = "";
    this.author = "";
    this.price = 0;
    this.category = "";
  }
  
  withName(name) {
    this.name = name;
    return this;
  }

  withAuthor(author) {
    this.author = author;
    return this;
  }

  withPrice(price) {
    this.price = price;
    return this;
  }

  withCategory(category) {
    this.category = category;
    return  this;
  }

  build() {
    return {
      name: this.name,
      author: this.author,
      prices: this.price,
      category: this.category
    }
  }
}

//调用建造者类
const book = new BookBuilder()
  .withName("高效能人士的七个习惯")
  .withAuthor("史蒂芬·柯维")
  .withPrice(51)
  .withCategory("励志")
  .build();

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

//书籍建造者类
class BookBuilder {
  constructor() {
    this.name = "";
    this.author = "";
    this.price = 0;
    this.category = "";
  
    Object.keys(this).forEach(key => {
      const withName = `with${key.substring(0, 1).toUpperCase()}${key.substring(1)}`;
      this[withName] = value => {
        this[key] = value;
        return this;
      }
    })
  }
  
  //调用建造者
  build() {
    const keysNoWithers = Object.keys(this).filter(key => typeof this[key] !== "function");

    return keysNoWithers.reduce((returnValue, key) => {
      return {
        ...returnValue,
        [key]: this[key]
      }
    }, {})
  }
}

const book = new BookBuilder()
  .withName("高效能人士的七个习惯")
  .withAuthor("史蒂芬·柯维")
  .withPrice(51)
  .withCategory("励志")
  .build();

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

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

//父类
class BaseBuilder {
  init() {
    Object.keys(this).forEach(key => {
      const withName = `with${key.substring(0, 1).toUpperCase()}${key.substring(1)}`;
      this[withName] = value => {
        this[key] = value;
        return this;
      }
    })
  }

  build() {
    const keysNoWithers = Object.keys(this).filter(key => typeof this[key] !== "function");

    return keysNoWithers.reduce((returnValue, key) => {
      return {
        ...returnValue,
        [key]: this[key]
      }
    }, {})
  }
}

//子类1: 书籍建造者类
class BookBuilder extends BaseBuilder {
  constructor() {
    super();

    this.name = "";
    this.author = "";
    this.price = 0;
    this.category = "";
    
    super.init();
  }
}

//子类2: 印刷厂建造者类
class printHouseBuilder extends BaseBuilder {
  constructor() {
    super();

    this.name = "";
    this.location = "";
    this.quality = "";

    super.init();
  }
}

//调用书籍建造者类
const book = new BookBuilder()
  .withName("高效能人士的七个习惯")
  .withAuthor("史蒂芬·柯维")
  .withPrice(51)
  .withCategory("励志")
  .build();


//调用印刷厂建造类
const printHouse = new printHouseBuilder()
  .withName("新华印刷厂")
  .withLocation("北京海淀区")
  .withQuality("A")
  .build();
总结

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

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

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/113424.html

相关文章

  • ES6重新认识JavaScript设计模式(): 建造模式

    摘要:书籍建造者类调用建造者高效能人士的七个习惯史蒂芬柯维励志上面的这个类和第一个例子的效果一样,但是长度确减少不少,在有更多属性的时候,减少的代码量会更为明显。参考内容设计模式张容铭 showImg(https://segmentfault.com/img/remote/1460000015147692); 1 什么是建造者模式? 建造者模式(Builder)是将一个复杂对象的构建层与其表...

    yuanxin 评论0 收藏0
  • ES6重新认识JavaScript设计模式(): 建造模式

    摘要:书籍建造者类调用建造者高效能人士的七个习惯史蒂芬柯维励志上面的这个类和第一个例子的效果一样,但是长度确减少不少,在有更多属性的时候,减少的代码量会更为明显。参考内容设计模式张容铭 showImg(https://segmentfault.com/img/remote/1460000015147692); 1 什么是建造者模式? 建造者模式(Builder)是将一个复杂对象的构建层与其表...

    endiat 评论0 收藏0
  • JavaScript设计模式系列建造模式

    摘要:优点建造者模式的封装性很好,对象本身与构建过程解耦。建造者模式很容易进行扩展。适用场景需要生成的对象具有复杂得内部结构且内部属性本身相互依赖建造者模式的代码实现建造者模式主要有个部分产品类建造者类指挥者类客户。建造者完成相应的部分。 建造者模式 建造者模式(builder pattern)比较简单,它属于创建型模式的一种,将一个复杂的对象分解成多个简单的对象来进行构建,将复杂的构建层与...

    CloudDeveloper 评论0 收藏0
  • 细谈JavaScript中的一些设计模式

    摘要:注意事项声明函数时候处理业务逻辑区分和单例的区别,配合单例实现初始化构造函数大写字母开头推荐注意的成本。简单工厂模式使用一个类通常为单体来生成实例。 @(书籍阅读)[JavaScript, 设计模式] 常见设计模式 一直对设计模式不太懂,花了一下午加一晚上的时间,好好的看了看各种设计模式,并总结了一下。 设计模式简介 设计模式概念解读 设计模式的发展与在JavaScript中的应用 ...

    30e8336b8229 评论0 收藏0
  • ES6重新认识JavaScript设计模式: 装饰器模式

    摘要:什么是装饰器模式向一个现有的对象添加新的功能,同时又不改变其结构的设计模式被称为装饰器模式,它是作为现有的类的一个包装。中的装饰器模式中有一个的提案,使用一个以开头的函数对中的及其属性方法进行修饰。 1 什么是装饰器模式 showImg(https://segmentfault.com/img/remote/1460000015970102?w=1127&h=563); 向一个现有的对...

    wendux 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<