「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」。
序言
今天我们要学习的设计模式叫做建造者模式,建造者模式就是帮助我们创建一个复杂对象的,它将一个复杂的对象的构建与它的结果分离,使得同样的构建过程可以创建不同的结果。和之前文章中的工厂模式的特点截然不同,工厂模式不注重过程,只注重结果。如果不知道工厂的模式的可以先看看这篇《玩转设计模式(简单工厂模式)》。
什么是建造者模式
建造者模式使用场景,大多出现在拥有很多重复的过程,但是最后的结果不同。 举个简单的例子 有一台自动炒菜机器,炒菜的逻辑都是写在机器程序里面,全部的步骤可能包含:
- 先放点油,然后加热
- 然后放入菜
- 然后不停拨动
- 然后放入调味品
- 然后装盘
我们发现,不管我们是想要炒白菜,还是炖肉,都要如上几个步骤,但是不同的菜,需要的油熟练不同,需要的时间不同,需要的调味品也不同,难道我们要分别为炒白菜和炖肉,分别定义一个如此长的工序吗,建造者模式可以让两种程序用一套逻辑生成。
建造者模式实例
class FriedDish {
name: string;
// 可选参数也可以使用 set,但是 ts 中直接在这里声明更方便, 当然如果是 private,需要使用 set 来封装
meatType?: string;
vegetableType?: string;
private breadNum?: number;
constructor(name: string) { // 如果我们不用建造者模式,那么产品类的 constructor 这里将要传入所有参数
this.name = name; // 必选参数可以放在这里,步骤具体实现可变的就抽出来
}
// 利用 ts 的 set 当然也是 okay 的,比如 set num(num){ this.breadNum = num; }
setBreadNum(num: number) {
this.breadNum = num;
}
}
// 原本放在产品类的构建步骤被转移到了建造者类,由具体的建造者实现
abstract class FriedDishBuilder {
abstract buildBread(breadNum: number): void;
abstract buildMeat(meatType: string): void;
abstract buildVegetable(vegetableTYpe: string): void;
abstract createHamburg(): FriedDish;
}
class FriedDishBeef extends FriedDishBuilder {
// 这里如果可以确定 name,就不需要用户再传入了
private FriedDish: FriedDish = new FriedDish('牛肉');
buildBread(breadNum: number): void {
console.log(`制作牛肉需要的 ${breadNum} 片面包`);
this.FriedDish.setBreadNum(breadNum);
}
buildMeat(meatType: string): void {
console.log(`制作牛肉需要的 ${meatType}`);
this.FriedDish.meatType = meatType;
}
buildVegetable(vegetableType: string): void {
console.log(`制作牛肉需要的 ${vegetableType}`);
this.FriedDish.vegetableType = vegetableType;
}
createHamburg(): FriedDish {
return this.FriedDish;
}
}
class FriedDishPork extends FriedDishBuilder {
private FriedDish: FriedDish = new FriedDish('猪肉');
buildBread(breadNum: number): void {
console.log(`制作猪肉需要的 ${breadNum} 片面包`);
this.FriedDish.setBreadNum(breadNum);
}
buildMeat(meatType: string): void {
console.log(`制作猪肉需要的 ${meatType}`);
this.FriedDish.meatType = meatType;
}
buildVegetable(vegetableType: string): void {
console.log(`制作猪肉需要的 ${vegetableType}`);
this.FriedDish.vegetableType = vegetableType;
}
createHamburg(): FriedDish {
return this.FriedDish;
}
}
// 我们用 director 来封装顺序,如果要改变工序,只要新增一个 director 或者新增一个 construct 即可
class HamburgDirector {
// 顺序1,包含三道工序
static construct1(builder: FriedDishBuilder, breadNum: number, meatType: string, vegetableType: string): FriedDish {
builder.buildBread(breadNum);
builder.buildMeat(meatType);
builder.buildVegetable(vegetableType);
return builder.createHamburg();
}
// 顺序2,包含两道工序
static construct2(builder: FriedDishBuilder, breadNum: number, meatType: string): FriedDish {
builder.buildMeat(meatType);
builder.buildBread(breadNum);
return builder.createHamburg();
}
}
const FriedDishBeef = new FriedDishBeef();
const FriedDishPork = new FriedDishPork();
HamburgDirector.construct1(FriedDishBeef, 2, 'beef', 'carrot');
HamburgDirector.construct2(FriedDishPork, 3, 'pork');
总结
我们通过上面的例子和说明了解到,当一个类的步骤相同时,我们可以通过改变步骤中参数,使得获取我们想要的结果,当我们需要新增的时候,也有了标准的规范和定义。非常方便管理。