如果今天我们想要开一间饮料店,饮料的组合包含了茶、糖,还有牛奶,於是我们可以建立一个 createTea
方法,并依据传入的参数,来决定最後的产品
class CreateMyTea {
static createTea(tea: boolean, sugar: boolean, milk: boolean): string[] {
const product = []
if (tea) {
product.push('tea')
}
if (milk) {
product.push('milk')
}
if (sugar) {
product.push('sugar')
}
return product
}
}
所以可以得到结果如下
const tea = CreateMyTea.createTea(true, true, false)
tea // ['tea', 'sugar']
const milkTea = CreateMyTea.createTea(true, true, true)
milkTea // ['tea', 'milke', 'sugar']
但这时候就会发现,如果饮料的原料越来越多,那们我们就必须不断地进入 CreateMyTea
扩充,另一方面,如果在这样的情况下,我们还想要限制原料「加入的顺序」,那麽 CreateMyTea
方法内部逻辑将会非常庞大,而且可能一团糟。
这时候,让我们来看看一个不一样的做法
首先,我们将所有加入原料的步骤拆成独立的抽象方法,并透过一个抽象类别 TeaBuilder
整理起来。在这里我们还没有放入实作的细节
abstract class TeaBuilder {
abstract addTea(): void
abstract addMilk(): void
abstract addSugar(): void
}
接下来,可以先来定义最终产品的样子,这里我们建立了 Tea
类别
class Tea {
parts: string[] = []
constructor(){}
}
然後,我们可以实作一个自己的 TeaBuilder
,并放入实作的细节
class MyTeaBuilder extends TeaBuilder {
private product: Tea
constructor() {
super()
this.reset()
}
reset(): void {
this.product = new Tea()
}
addTea(): void {
this.product.parts.push('tea')
}
addSugar(): void {
this.product.parts.push('sugar')
}
addMilk(): void {
this.product.parts.push('milk')
}
getProduct(): Tea {
const result = this.product
this.reset()
return result
}
}
有了我们自己的 builder 之後,我们就可以建立一个 director,来负责指挥我们最终的产品该如何被生产出来。在下面的例子当中可以看到,我们有三种建立产品的方法:buildTeaKosong
, buildTea
, buildMilkTea
,当中我们定义了生产该产品需要的「步骤」和「顺序」
class Director {
builder: MyTeaBuilder
constructor(){}
setBuilder(builder: MyTeaBuilder): void {
this.builder = builder
}
buildTeaKosong(): Tea {
this.builder.addTea()
return this.builder.getProduct()
}
buildTea(): Tea {
this.builder.addTea()
this.builder.addSugar()
return this.builder.getProduct()
}
buildMilkTea(): Tea {
this.builder.addTea()
this.builder.addSugar()
this.builder.addMilk()
return this.builder.getProduct()
}
}
最後,我们可以呼叫这个 director,来帮助我们生产出我们期待中的产品!
// 建立 director
const myDirector = new Director()
myDirector.setBuilder(new MyTeaBuilder())
const teaKosong = myDirector.buildTeaKosong()
teaKosong.parts // ['tea']
const tea = myDirector.buildTea()
tea.parts // ['tea', 'sugar']
const milkTea = myDirector.buildMilkTea()
milkTea.parts // ['tea', 'sugar', 'milk']
另一方面,我们也可以跳过 director 的指挥,自己操作 builder 制造新产品
myDirector.builder.addTea()
myDirector.builder.addMilk()
const newProduct = myDirector.builder.getProduct()
newProduct.parts // ['tea', 'milk']
建造者模式透过 builder 和 director 的合作,帮助我们管理复杂的生产步骤与顺序,同时提供生产不同产品的弹性。建造者模式的优点在於,我们可以弹性的使用各种生产步骤,并且重复使用这些步骤,来面对复杂的需求。
在上面的例子当中,builder 负责管理各个生产步骤的实作,而 director 管理步骤的组合与顺序。
所以对使用者来说,我们不需要知道实际生产的实作方式、顺序为何,只要呼叫对的 director 和其方法,就能够得到我们想要的产品,譬如 milkTeak。
工厂模式专注在产出的结果,而建造者模式较多关注在生产的步骤、组合和顺序上面。另一方面,工厂模式产出的产品为同一(或类似)性质的产品,但透过建造者模式,我们可以创造出非常多变化的产品
经过这三十天的每天发文 每天督促自己学习新的东西并记录下来 没想到已经坚持到最後一天了!! 虽然其实...
大家在玩CMS之前应该都有先在本地端做测试的习惯吧,那应该会有遇到那种像是使用了XAMPP在本地端架...
Use Case Spec 这边以之前的 use case 当作例子来撰写测试。 首先要能快速地建立...
上回介绍闭包概念以及闭包大致运用,这次则介绍实做比较常用闭包的几种模式 工厂模式 上个章节有介绍到,...
购买後需详阅公开声明书 会下这标题的原因是,主题真正购买後的安装设定,真的需要参考网路文章才能少走很...