模式补全
这一节按 八面剖析以理解一个概念 / ljg-learn 的思路整理为 Markdown 版本:先定锚,再用八个方向切开概念,最后压缩成公式、例子、类图和检验题。
定锚
建造者模式(生成器模式)(创建型)的通行定义:把复杂对象的构建过程拆成多个步骤,让同样的构建过程可以产生不同表示。
常见误解:它不是链式调用的同义词;链式 API 只是常见外观,核心是分步骤构建复杂对象。
核心词素:Builder 强调 build 的过程性:对象不是一下子 new 出来,而是被一步步组装。
八刀
历史
它来自复杂对象构造参数过多、构造顺序重要的场景。GoF 版本还强调 Director 对构建步骤的编排。
辩证
反面是超长构造函数和到处散落的配置拼装。更高理解是:把构建过程本身对象化。
现象
像装修房子,先定地板、再定墙面、再定灯光。不同套餐共享步骤,但最终风格不同。
语言
Builder 强调 build 的过程性:对象不是一下子 new 出来,而是被一步步组装。
形式
object = builder.stepA().stepB().build()。当对象构造很简单时,它会变成仪式感过重。
存在
它让开发者把“创建完成的一瞬间”扩展成“可管理的创建过程”。
美感
它美在层层成形:像模型从骨架到外壳,一步一步出现完整结构。
元反思
我们常用“施工队”理解它,这会遮住不可变对象和校验的重要性。换成“编译流水线”隐喻,会更重视最终 build 的边界。
内观
我是对象成形前的工作台。你把选项交给我,我负责顺序、默认值和最终校验。build 之前,一切都还可以调整。
八刀共同指向的深层结构:建造者模式(生成器模式)不是为了“炫技”,而是在某个变化点上建立边界,让稳定部分继续稳定,让变化部分有自己的位置。
压缩
公式:建造者 = 分步配置 + 构建边界 + 复杂对象
一句话:建造者把复杂构造从一个巨大构造函数里拆成可读、可控的步骤。
结构图:
Client -> Builder steps -> build() -> Product动机/意图
当一个对象构造参数很多、步骤有顺序、默认值复杂,或需要在最后统一校验时,直接使用构造函数会变得难读且脆弱。生成器模式的意图是把复杂对象的构建过程拆成清晰步骤,并把最终产物的创建边界收束到 build()。
结构/角色
Product:最终被构建出来的复杂对象。Builder:抽象建造者,声明构建各部分的方法和结果获取方法。ConcreteBuilder:具体建造者,保存中间状态,按步骤组装产品。Director:指挥者,可选角色,负责按固定顺序调用建造步骤。Client:客户端配置建造者,或让指挥者组织构建过程。
典型 UML
classDiagram class Director { +construct(builder: Builder): void } class Builder { <<interface>> +buildPartA(): void +buildPartB(): void +getResult(): Product } class ConcreteBuilder class Product Builder <|.. ConcreteBuilder Director ..> Builder ConcreteBuilder ..> Product
使用场景
- 构造函数参数过多,且参数之间存在约束。
- 同一构建流程可以生成不同表示或不同配置的对象。
- 需要把构建过程、默认值和最终校验集中管理。
- 创建对象时有多个可选步骤,链式配置能显著提升可读性。
正例:TypeScript
class Meal {
private food = ""
private drink = ""
setFood(food: string) {
this.food = food
}
setDrink(drink: string) {
this.drink = drink
}
show() {
console.log(`meal: ${this.food} + ${this.drink}`)
}
}
abstract class MealBuilder {
protected meal = new Meal()
abstract buildFood(): void
abstract buildDrink(): void
getMeal() {
return this.meal
}
}
class HamburgerMealBuilder extends MealBuilder {
buildFood() {
this.meal.setFood("hamburger")
}
buildDrink() {
this.meal.setDrink("cola")
}
}
class ChickenWrapMealBuilder extends MealBuilder {
buildFood() {
this.meal.setFood("chicken wrap")
}
buildDrink() {
this.meal.setDrink("juice")
}
}
class Waiter {
constructor(private builder: MealBuilder) {}
setBuilder(builder: MealBuilder) {
this.builder = builder
}
construct() {
this.builder.buildFood()
this.builder.buildDrink()
return this.builder.getMeal()
}
}
const waiter = new Waiter(new HamburgerMealBuilder())
const mealA = waiter.construct()
mealA.show()
waiter.setBuilder(new ChickenWrapMealBuilder())
const mealB = waiter.construct()
mealB.show()正例:UML 类图
classDiagram class Meal { -food: string -drink: string +setFood(food: string): void +setDrink(drink: string): void +show(): void } class MealBuilder { <<abstract>> #meal: Meal +buildFood(): void +buildDrink(): void +getMeal(): Meal } class HamburgerMealBuilder { +buildFood(): void +buildDrink(): void } class ChickenWrapMealBuilder { +buildFood(): void +buildDrink(): void } class Waiter { -builder: MealBuilder +setBuilder(builder: MealBuilder): void +construct(): Meal } MealBuilder <|-- HamburgerMealBuilder MealBuilder <|-- ChickenWrapMealBuilder MealBuilder --> Meal Waiter --> MealBuilder
反例:TypeScript
class Meal {
constructor(
public food: string,
public drink: string,
) {}
}
function createMeal(type: "hamburger" | "chickenWrap") {
if (type === "hamburger") {
return new Meal("hamburger", "cola")
}
return new Meal("chicken wrap", "juice")
}反例:UML 类图
classDiagram class Client class Meal { +Meal(food, drink) } class MealFactoryFunction { +createMeal(type): Meal } Client ..> MealFactoryFunction MealFactoryFunction ..> Meal : branch assembly
案例
建造者模式可以用于描述KFC如何创建套餐:套餐是一个复杂对象,它一般包含主食(如汉堡、鸡肉卷等)和饮料(如果汁、可乐等)等组成部分,不同的套餐有不同的组成部分,而KFC的服务员可以根据顾客的要求,一步一步装配这些组成部分,构造一份完整的套餐,然后返回给顾客。
掌握检验
- 建造者模式和普通链式调用有什么区别?
- 什么时候超长构造函数应该被替换为 Builder?
- build 方法为什么适合放最终校验?