基本概念
建造者模式(Builder Pattern)又称生成器模式,分步构建一个复杂对象,并允许按步骤构造。同样的构建过程可以采用不同的表示,将一个复杂对象的构建层与其表示层分离。
在工厂模式中,我们并不关心创建过程,只关心创建的结果,其创建的结果也都是一个整体。而建造者模式则关心的是对象创建的过程,因此我们通常将创建的复杂对象的模块化,使得被创建的对象的每一个子模块都可以得到高质量的复用。
现实生活中的例子
造车:
我们要早一台车,而车的零部件是非常多的,比如:发动机、轮子、车身、内饰等等。一台车是由这些零件分别生产好,再一件一件拼装起来的,不可能一气呵成整体去生产一台车的所有。造车的过程就非常符合建造者模式的概念。
造手机:
生产一部手机也需要很多零件,主板、显示屏、外壳、芯片等等,每一个零件都装配好久制造出了一部手机。
类似的例子还有很多,就不一一列举了。
应用场景
- 相同的方法,不同的执行顺序,产生不一样的产品时,可以采用建造者模式;
- 产品的组成部件类似,通过组装不同的组件获得不同产品时,可以采用建造者模式;
优缺点
优点:
- 使用建造者模式可以使产品的构建流程和产品的表现分离,也就是将产品的创建算法和产品组成的实现隔离,访问者不必知道产品部件实现的细节;
- 扩展方便,如果希望生产一个装配顺序或方式不同的新产品,那么直接新建一个指挥者即可,不用修改既有代码,符合开闭原则;
- 更好的复用性,建造者模式将产品的创建算法和产品组成的实现分离,所以产品创建的算法可以复用,产品部件的实现也可以复用,带来很大的灵活性;
缺点:
- 建造者模式一般适用于产品之间组成部件类似的情况,如果产品之间差异性很大、复用性不高,那么不要使用建造者模式;
- 实例的创建增加了许多额外的结构,无疑增加了许多复杂度,如果对象粒度不大,那么我们最好直接创建对象;
实现
实现建造者模式通常需要知道几个概念:
-
Director,指挥者,调用各种零部件,实现装配工作,最后返回成品。
-
Builder,建造者,含有不同部件的生成方式,供指挥者调用,但不带任何装配流程。
-
Product,产品,要返回给访问者的复杂对象。
以造车为例:汽车厂家就是指挥者(Director),负责将不同的部件组装成最后的产品(Product),而部件的供应商,比如生成车轮的厂家就相当于建造者(Builder)。
结合链式模式,代码如下:
class CarBuilder {
constructor(weight, height, color, name, type) {
this.weight = weight
this.height = height
this.color = color
this.name = name
this.type = type
}
buildTyre(type) {
const tyre = {}
switch (type) {
case 'small':
tyre.tyreType = '小号轮胎'
tyre.tyreIntro = '正在使用小号轮胎'
break
case 'normal':
tyre.tyreType = '中号轮胎'
tyre.tyreIntro = '正在使用中号轮胎'
break
case 'big':
tyre.tyreType = '大号轮胎'
tyre.tyreIntro = '正在使用大号轮胎'
break
default:
break
}
this.tyre = tyre
return this
}
buildEngine(type) {
const engine = {}
switch (type) {
case 'small':
engine.engineType = '小马力发动机'
engine.engineIntro = '正在使用小马力发动机'
break
case 'normal':
engine.engineType = '中马力发动机'
engine.engineIntro = '正在使用中马力发动机'
break
case 'big':
engine.engineType = '大马力发动机'
engine.engineIntro = '正在使用大马力发动机'
break
default:
break
}
this.engine = engine
return this
}
setPropertyFuncChain() {
Object.getOwnPropertyNames(this)
.forEach(key => {
const funcName = 'set' + key.replace(/^\w/g, str => str.toUpperCase())
this[funcName] = value => {
this[key] = value
return this
}
})
return this
}
}
class CarFactory1 {
constructor() {
return new CarBuilder().setPropertyFuncChain()
.setWeight('2ton')
.setHeight('2000mm')
.setColor('white')
.setName('car1')
.setType('AMG')
.buildTyre('small')
.buildEngine('big')
}
}
class CarFactory2 {
constructor() {
return new CarBuilder().setPropertyFuncChain()
.setWeight('2.1ton')
.setHeight('2010mm')
.setColor('white')
.setName('car2')
.setType('AMG')
.buildTyre('normal')
.buildEngine('normal')
}
}
const car1 = new CarFactory1()
const car2 = new CarFactory2()
console.log(car1)
console.log(car2)