玩转设计模式(建造者模式)

356 阅读3分钟

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」。

序言

今天我们要学习的设计模式叫做建造者模式,建造者模式就是帮助我们创建一个复杂对象的,它将一个复杂的对象的构建与它的结果分离,使得同样的构建过程可以创建不同的结果。和之前文章中的工厂模式的特点截然不同,工厂模式不注重过程,只注重结果。如果不知道工厂的模式的可以先看看这篇《玩转设计模式(简单工厂模式)》

什么是建造者模式

建造者模式使用场景,大多出现在拥有很多重复的过程,但是最后的结果不同。 举个简单的例子 有一台自动炒菜机器,炒菜的逻辑都是写在机器程序里面,全部的步骤可能包含:

  1. 先放点油,然后加热
  2. 然后放入菜
  3. 然后不停拨动
  4. 然后放入调味品
  5. 然后装盘

我们发现,不管我们是想要炒白菜,还是炖肉,都要如上几个步骤,但是不同的菜,需要的油熟练不同,需要的时间不同,需要的调味品也不同,难道我们要分别为炒白菜和炖肉,分别定义一个如此长的工序吗,建造者模式可以让两种程序用一套逻辑生成。

建造者模式实例

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');

总结

我们通过上面的例子和说明了解到,当一个类的步骤相同时,我们可以通过改变步骤中参数,使得获取我们想要的结果,当我们需要新增的时候,也有了标准的规范和定义。非常方便管理。