1什么是BuilderMode?建造者模式(Builder)将一个复杂对象的构造层与其表示层分开。同一个构造过程可以用不同的表示法。建造者模式的特点是一步一步地建造一个复杂的物体。可以以不同的组合或顺序构建具有不同含义的对象。通常,用户不需要知道构造的细节。他们通常使用链式调用来进行构建过程,最后调用build方法生成最终对象。同样作为创建型设计模式,需要注意与工厂模式的区别。虽然工厂也在创建对象,但是如何创建对象并不重要。工厂模式关注创建的结果;而建造者模式不仅获取结果,还参与创建。适用于创建复杂复合对象的特定过程。2ES6中的Builder模式我们假设一个出版社图书后台录入系统的业务场景。书籍有四个必填信息,即:书名、作者、价格、分类;我们想创建一个书籍对象返回到后端。让我们逐步了解使用ES6语法结合构建器模式创建对象。//BookbuilderclassclassBookBuilder{constructor(){this.name='';this.author='';这个.price=0;this.category='';}withName(name){this.name=returnthis;}withAuthor(author){this.author=author;归还这个;}withPrice(价格){this.price=price;归还这个;}withCategory(category){this.category=category;归还这个;}build(){return{name:this.name,author:this.author,prices:this.price,category:this.category}}}//调用构建器类constbook=newBookBuilder().withName("高效能人士的七个习惯").withAuthor('StephenCovey').withPrice(51).withCategory('Inspirational').build();以上是通过我的BookBuildercreator类的编写和调用方法,但是它只是一个有4个属性的对象,我们用了这么多代码来创建,远比在构造函数中直接传参创建一个对象要复杂的多。这是因为我们在创建过程中有太多的withxxxx方法。我们实际上可以自动创建这样的withxxxx方法来简化代码。//BookbuilderclassclassBookBuilder{constructor(){this.name='';this.author='';这个.price=0;this.category='';Object.keys(this).forEach(key=>{constwithName=`with${key.substring(0,1).toUpperCase()}${key.substring(1)}`;this[withName]=value=>{this[key]=value;returnthis;}})}//callbuilderbuild(){constkeysNoWithers=Object.keys(this).filter(key=>typeofthis[key]!=='函数');returnkeysNoWithers.reduce((returnValue,key)=>{return{...returnValue,[key]:this[key]}},{})}}constbook=newBookBuilder().withName("七个习惯高效能人士").withAuthor('StephenCovey').withPrice(51).withCategory('Inspirational').build();上面的BookBuilder类和第一个例子效果一样,但是篇幅确实减少了很多。当属性越多时,减少的代码量会越明显。我们会在调用构造函数时自动创建所有带有xxxx的构造方法。这里我们使用了ES6的一些新语法:Object.keys获取对象属性数组,以及合并对象的语法。虽然这种写法会比第一种方式更难理解,但是这种写法真正的作用在于,当我们需要很多builder类的时候,我们可以把上面自动创建withxxx的代码抽取出来作为父类进行build。在创建其他构建器类的时候继承这个父类,这样就可以非常方便的创建多个构建器类。//父类BaseBuilder{init(){Object.keys(this).forEach(key=>{constwithName=`with${key.substring(0,1).toUpperCase()}${key.substring(1)}`;this[withName]=value=>{this[key]=value;returnthis;}})}build(){constkeysNoWithers=Object.keys(this).filter(key=>typeofthis[key]!=='函数');returnkeysNoWithers.reduce((returnValue,key)=>{return{...returnValue,[key]:this[key]}},{})}}//子类1:BookBuilder类classBookBuilderextendsBaseBuilder{constructor(){极好的();this.name='';this.author='';这个.price=0;this.category='';超级初始化();}}//子类2:印刷厂建造者类printHouseBuilderextendsBaseBuilder{constructor(){super();this.name='';this.location='';this.quality='';超级.init();}}//调用图书生成器类constbook=newBookBuilder().withName("高效能人士的七个习惯").withAuthor('StephenCovey').withPrice(51).withCategory('励志').build();//调用印刷厂构造类constprintHouse=newprintHouseBuilder().withName('新华印刷厂').withLocation('北京市海淀区').withQuality('A').build();总结在上面提到的几种工厂模式中,它们都有一个共同的特点,就是对象的创建过程是未知的,我们在调用一个函数后返回最终的结果对象但是在创建者模式中,我们关心的是对象创作过程。我们通常将创建复杂对象的类模块化。在ES6中,我们使用import和export的语法来灵活地引用和导出这些模块,以便我们的Build模式最终产生一个结果对象。可见使用建造者模式只适合于创建极其复杂的对象。在实际的前端业务中,当没有创建这种极其复杂的对象时,应该直接使用对象字面量或者工厂模式来创建对象。参考内容:[1]JavaScriptBuilders探秘——RyanOglesby[2]《 JavaScript设计模式 》——张荣明
