Builder-Pattern(建造者模式)

建造者模式(Builder Pattern):组装具有复杂结构的实例。这种类型的设计模式属于创建型模式。

介绍

  • 意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
  • 主要解决:主要解决在软件系统中,有时候面临着”一个复杂对象”的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。
  • 何时使用:一些基本部件不会变,而其组合经常变化的时候。
  • 应用实例: 去肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的”套餐”。
  • 优点:
    1、建造者独立,易扩展。
    2、便于控制细节风险。
  • 缺点:
    1、产品必须有共同点,范围有限制。
    2、如内部变化复杂,会有很多的建造类。
  • 使用场景:
    1、需要生成的对象具有复杂的内部结构。
    2、需要生成的对象内部属性本身相互依赖。

注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

示例

type.ts 定义食物接口和包装接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 食物接口
*/
export interface Food {
name(): string;
packing(): Packing;
price(): number;
}
/**
* 包装接口
*/
export interface Packing {
pack(): string
}

Wrapper.ts 纸质包装类

1
2
3
4
5
6
7
import { Packing } from "./type";

export default class Wrapper implements Packing {
public pack(): string {
return "Wrapper";
}
}

Bottle.ts 定义瓶装类

1
2
3
4
5
6
7
import { Packing } from "./type";

export default class Bottle implements Packing {
public pack(): string {
return "Bottle";
}
}

Burger.ts 实现食物接口没定义包装为纸质

1
2
3
4
5
6
7
8
9
10
11
import { Food, Packing } from "./type";
import Wrapper from "./Wrapper";

export default abstract class Burger implements Food {
public abstract name(): string;
public packing(): Packing {
return new Wrapper();
}

public abstract price(): number;
}

ColdDrink.ts 冷饮类实现食物接口,并指定包装为瓶装

1
2
3
4
5
6
7
8
9
10
11
import { Food, Packing } from "./type";
import Bottle from "./Bottle";

export default abstract class ColdDrink implements Food {
public abstract name(): string;
public packing(): Packing {
return new Bottle();
}

public abstract price(): number;
}

VegBurger.ts 蔬菜汉堡类

1
2
3
4
5
6
7
8
9
10
import Burger from "./Burger";

export default class VegBurger extends Burger {
public price(): number {
return 25;
}
public name(): string {
return "Veg Burger";
}
}

ChickenBurger.ts 鸡肉堡类

1
2
3
4
5
6
7
8
9
10
11
12
import Burger from "./Burger";

export default class ChickenBurger extends Burger {

public price(): number {
return 50.5;
}

public name(): string {
return "Chicken Burger";
}
}

Pepsi.ts 百事饮料类

1
2
3
4
5
6
7
8
9
10
11
12
import ColdDrink from "./ColdDrink";

export default class Pepsi extends ColdDrink {

public price(): number {
return 35.0;
}

public name(): string {
return "Pepsi";
}
}

Coke.ts 可口可乐类继承自冷饮

1
2
3
4
5
6
7
8
9
10
11
import ColdDrink from "./ColdDrink";

export default class Coke extends ColdDrink {

public price(): number {
return 30.0;
}
public name(): string {
return "Coke";
}
}

Meal.ts 套餐类,里面有食物和总价

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import { Food } from "./type";

export default class Meal {
private items = new Array<Food>();

public addItem(item: Food): void {
this.items.push(item);
}

public getCost(): number {
let cost = 0;
for (const item of this.items) {
cost += item.price();
}
return cost;
}

public showItems(): void {
for (const item of this.items) {
console.log(`Food : ${item.name()}, Packing : ${item.packing().pack()}, Price : ${item.price()}`);
}
}
}

MealBuilder.ts 创建套餐,有蔬菜和没蔬菜的套餐

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import Meal from "./Meal";
import VegBurger from "./VegBurger";
import Coke from "./Coke";
import ChickenBurger from "./ChickenBurger";
import Pepsi from "./Pepsi";

export default class MealBuilder {

public prepareVegMeal(): Meal {
const meal = new Meal();
meal.addItem(new VegBurger());
meal.addItem(new Coke());
return meal;
}

public prepareNonVegMeal(): Meal {
const meal = new Meal();
meal.addItem(new ChickenBurger());
meal.addItem(new Pepsi());
return meal;
}
}

index.ts

1
2
3
4
5
6
7
8
9
10
11
12
13
import MealBuilder from "./MealBuilder";

const mealBuilder = new MealBuilder();

const vegMeal = mealBuilder.prepareVegMeal();
console.log("-----Veg Meal-------");
vegMeal.showItems();
console.log("Total Cost: " + vegMeal.getCost());

const nonVegMeal = mealBuilder.prepareNonVegMeal();
console.log("-----Non-Veg Meal-----");
nonVegMeal.showItems();
console.log("Total Cost: " + nonVegMeal.getCost());

result

1
2
3
4
5
6
7
8
-----Veg Meal-------
Food : Veg Burger, Packing : Wrapper, Price : 25
Food : Coke, Packing : Bottle, Price : 30
Total Cost: 55
-----Non-Veg Meal-----
Food : Chicken Burger, Packing : Wrapper, Price : 50.5
Food : Pepsi, Packing : Bottle, Price : 35
Total Cost: 85.5

类图

角色

  • Builder(建造者)
    Builder角色负责定义用于生产实例的接口,Builder角色中有用于生产实例的方法
  • ConcreteBuilder(具体的建造者)
    ConcreteBuilder角色时负责实现Builder角色的接口的类,定义了在生产实例时实际被调用的犯法,此外,在ConcreteBuilder中还定义了获取最终生产结果的方法
  • Director(监工)
    Director角色负责使用Builder角色的接口来生产实例,不依赖于ConcreteBuilder角色。它只调用在Builder角色中被定义的方法
  • Client(使用者)
    该角色使用了Builder模式。