设计模式之建造者模式&模版模式、策略模式

建造者模式深度解析:构建与表示的分离

本文档帮助理解建造者模式的核心概念,以及与模板方法模式、策略模式的区别与联系。


一、建造者模式核心概念

1.1 什么是"构建"与"表示"

建造者模式的经典定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

构建(Construction)

构建 = 组装对象的过程

  • 关注点:怎么做(How)
  • 内容:一步步创建对象的各个部分
  • 特点:构建步骤/流程通常是固定的
表示(Representation)

表示 = 最终生成的对象的具体形态/结构/配置

  • 关注点:做什么(What)
  • 内容:最终对象的属性组合、结构形态
  • 特点:同样的构建过程可以产生完全不同的表示

1.2 核心理解

相同的构建过程,可以产生不同的表示。

这就是"分离"的核心含义:构建算法(步骤)是固定的,但最终生成的对象形态可以不同。

1.3 经典示例:房屋建造

markdown 复制代码
构建过程(固定步骤):
1. 打地基
2. 建墙体
3. 安装门窗
4. 装修

不同的表示(最终产物):
├── 表示 A:木质别墅
│   ├── 木地基 + 木墙 + 木门窗 + 豪华装修
├── 表示 B:砖混公寓
│   ├── 水泥地基 + 砖墙 + 铝合金门窗 + 简装
└── 表示 C:钢结构厂房
    └── 钢地基 + 彩钢板墙 + 卷帘门 + 无装修

构建过程完全一样(都是 4 步),但最终"表示"完全不同。

1.4 代码示例

java 复制代码
// 产品类(表示)
class House {
    private String foundation;   // 地基
    private String wall;         // 墙体
    private String door;         // 门窗
    private String decoration;   // 装修
    
    // 不同的表示 = 不同的属性组合
    public String getDescription() {
        return foundation + " + " + wall + " + " + door + " + " + decoration;
    }
}

// 抽象建造者
interface HouseBuilder {
    void buildFoundation();
    void buildWall();
    void buildDoor();
    void buildDecoration();
    House getHouse();
}

// 具体建造者 1:木质别墅
class WoodenHouseBuilder implements HouseBuilder {
    private House house = new House();
    
    public void buildFoundation() { house.setFoundation("木地基"); }
    public void buildWall() { house.setWall("木墙"); }
    public void buildDoor() { house.setDoor("木门窗"); }
    public void buildDecoration() { house.setDecoration("豪华装修"); }
    public House getHouse() { return house; }
}

// 具体建造者 2:砖混公寓
class BrickHouseBuilder implements HouseBuilder {
    private House house = new House();
    
    public void buildFoundation() { house.setFoundation("水泥地基"); }
    public void buildWall() { house.setWall("砖墙"); }
    public void buildDoor() { house.setDoor("铝合金门窗"); }
    public void buildDecoration() { house.setDecoration("简装"); }
    public House getHouse() { return house; }
}

// 指挥者(控制构建过程)
class Director {
    private HouseBuilder builder;
    
    public void setBuilder(HouseBuilder builder) {
        this.builder = builder;
    }
    
    public House construct() {
        builder.buildFoundation();    // 步骤 1
        builder.buildWall();          // 步骤 2
        builder.buildDoor();          // 步骤 3
        builder.buildDecoration();    // 步骤 4
        return builder.getHouse();    // 返回最终表示
    }
}

// 客户端使用
public class Client {
    public static void main(String[] args) {
        Director director = new Director();
        
        // 构建木质别墅
        director.setBuilder(new WoodenHouseBuilder());
        House woodenHouse = director.construct();
        System.out.println(woodenHouse.getDescription());
        // 输出:木地基 + 木墙 + 木门窗 + 豪华装修
        
        // 构建砖混公寓
        director.setBuilder(new BrickHouseBuilder());
        House brickHouse = director.construct();
        System.out.println(brickHouse.getDescription());
        // 输出:水泥地基 + 砖墙 + 铝合金门窗 + 简装
    }
}

1.5 构建 vs 表示 对比表

维度 构建(Construction) 表示(Representation)
含义 组装对象的步骤和过程 最终生成的对象形态
关注点 怎么做(How) 做什么(What)
变化性 构建步骤通常固定 表示可以多样化
角色 Director + Builder 接口 具体 Builder 实现类
示例 打地基→建墙→装门→装修 木质别墅 / 砖混公寓 / 钢结构厂房

1.6 另一个例子:SQL 查询构建器

java 复制代码
// 构建过程(固定步骤)
class SQLQueryBuilder {
    private StringBuilder sql = new StringBuilder();
    
    public SQLQueryBuilder select(String columns) {
        sql.append("SELECT ").append(columns);
        return this;
    }
    
    public SQLQueryBuilder from(String table) {
        sql.append(" FROM ").append(table);
        return this;
    }
    
    public SQLQueryBuilder where(String condition) {
        sql.append(" WHERE ").append(condition);
        return this;
    }
    
    public SQLQueryBuilder orderBy(String column) {
        sql.append(" ORDER BY ").append(column);
        return this;
    }
    
    public String build() {
        return sql.toString();
    }
}

// 不同的表示(最终 SQL 语句)
public class Client {
    public static void main(String[] args) {
        SQLQueryBuilder builder = new SQLQueryBuilder();
        
        // 表示 1
        String sql1 = builder.select("id, name")
                             .from("users")
                             .where("age > 18")
                             .orderBy("name")
                             .build();
        // SELECT id, name FROM users WHERE age > 18 ORDER BY name
        
        // 表示 2
        String sql2 = builder.select("*")
                             .from("orders")
                             .where("status = 'paid'")
                             .build();
        // SELECT * FROM orders WHERE status = 'paid'
    }
}

构建过程相同 (都是 select→from→where→orderBy→build),但表示不同(生成的 SQL 语句不同)。


二、建造者模式 vs 模板方法模式

2.1 相似点

维度 相似之处
步骤固定 都有固定的执行步骤/流程
子类实现细节 都由子类实现具体步骤
流程控制 都由父类/指挥者控制流程

2.2 核心差异

arduino 复制代码
模板方法模式:
├── 关注点:算法流程的骨架
├── 变化点:某些步骤的具体实现
├── 输出:同一个算法的不同变体
└── 示例:冲泡饮料(烧水→冲泡→倒入杯子→加调料)
         咖啡和茶的区别在于"冲泡"和"加调料"步骤

建造者模式:
├── 关注点:复杂对象的构建过程
├── 变化点:每一步构建的具体内容
├── 输出:完全不同的对象表示
└── 示例:建造房屋(打地基→建墙→装门→装修)
         木质别墅和砖混公寓的每一步都不同

2.3 代码对比

java 复制代码
// ==================== 模板方法模式 ====================
abstract class Beverage {
    // 固定流程(模板方法)
    final void prepareRecipe() {
        boilWater();        // 固定步骤
        brew();             // 抽象步骤,子类实现
        pourInCup();        // 固定步骤
        addCondiments();    // 抽象步骤,子类实现
    }
    
    void boilWater() { System.out.println("烧水"); }
    void pourInCup() { System.out.println("倒入杯子"); }
    
    abstract void brew();
    abstract void addCondiments();
}

class Coffee extends Beverage {
    void brew() { System.out.println("冲泡咖啡"); }
    void addCondiments() { System.out.println("加糖和牛奶"); }
}

class Tea extends Beverage {
    void brew() { System.out.println("浸泡茶叶"); }
    void addCondiments() { System.out.println("加柠檬"); }
}

// 使用
Beverage coffee = new Coffee();
coffee.prepareRecipe();
// 输出:烧水 → 冲泡咖啡 → 倒入杯子 → 加糖和牛奶

Beverage tea = new Tea();
tea.prepareRecipe();
// 输出:烧水 → 浸泡茶叶 → 倒入杯子 → 加柠檬

// 注意:输出都是 Beverage 类型,只是某些步骤不同


// ==================== 建造者模式 ====================
interface HouseBuilder {
    void buildFoundation();  // 每一步都不同
    void buildWall();
    void buildDoor();
    void buildDecoration();
    House getHouse();        // 返回完全不同的对象
}

class WoodenHouseBuilder implements HouseBuilder {
    private House house = new House();
    
    void buildFoundation() { house.setFoundation("木地基"); }
    void buildWall() { house.setWall("木墙"); }
    void buildDoor() { house.setDoor("木门窗"); }
    void buildDecoration() { house.setDecoration("豪华装修"); }
    House getHouse() { return house; }
}

class BrickHouseBuilder implements HouseBuilder {
    private House house = new House();
    
    void buildFoundation() { house.setFoundation("水泥地基"); }
    void buildWall() { house.setWall("砖墙"); }
    void buildDoor() { house.setDoor("铝合金门窗"); }
    void buildDecoration() { house.setDecoration("简装"); }
    House getHouse() { return house; }
}

// 使用
Director director = new Director();

director.setBuilder(new WoodenHouseBuilder());
House woodenHouse = director.construct();
// 输出:木地基 + 木墙 + 木门窗 + 豪华装修

director.setBuilder(new BrickHouseBuilder());
House brickHouse = director.construct();
// 输出:水泥地基 + 砖墙 + 铝合金门窗 + 简装

// 注意:输出是完全不同的 House 对象

2.4 关键区别总结

对比维度 模板方法模式 建造者模式
目的 定义算法骨架,子类实现部分步骤 分离构建过程与表示,创建复杂对象
变化范围 部分步骤不同 所有步骤都不同
输出结果 同一类型的不同变体 完全不同的对象表示
流程控制 抽象类中的模板方法 独立的 Director 类
继承关系 子类继承抽象类 实现者实现接口
典型场景 框架设计、算法骨架 文档生成、UI 构建、SQL 构建

三、建造者模式 vs 策略模式

3.1 相似点

维度 相似之处
选择机制 都可以根据需要选择不同的实现
接口抽象 都通过接口/抽象类定义契约
运行时切换 都可以在运行时切换实现

3.2 核心差异

markdown 复制代码
策略模式:
├── 关注点:算法的可互换性
├── 变化点:同一个操作的不同算法
├── 输出:相同的结果类型,不同的计算方式
└── 示例:排序策略(快速排序、归并排序、冒泡排序)
         输入相同,输出相同,只是算法不同

建造者模式:
├── 关注点:对象构建的可扩展性
── 变化点:构建过程的每一步
├── 输出:完全不同的对象形态
└── 示例:房屋建造者(木质、砖混、钢结构)
         输入相同(构建步骤),输出完全不同

3.3 代码对比

java 复制代码
// ==================== 策略模式 ====================
interface SortStrategy {
    void sort(int[] array);  // 同一个操作,不同算法
}

class QuickSort implements SortStrategy {
    public void sort(int[] array) {
        System.out.println("使用快速排序");
        // 快速排序实现...
    }
}

class MergeSort implements SortStrategy {
    public void sort(int[] array) {
        System.out.println("使用归并排序");
        // 归并排序实现...
    }
}

class SortContext {
    private SortStrategy strategy;
    
    public void setStrategy(SortStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void sort(int[] array) {
        strategy.sort(array);
    }
}

// 使用
SortContext context = new SortContext();
int[] data = {3, 1, 4, 1, 5};

context.setStrategy(new QuickSort());
context.sort(data);
// 输出:使用快速排序 → [1, 1, 3, 4, 5]

context.setStrategy(new MergeSort());
context.sort(data);
// 输出:使用归并排序 → [1, 1, 3, 4, 5]

// 注意:输入相同,输出相同,只是算法不同


// ==================== 建造者模式 ====================
interface HouseBuilder {
    void buildFoundation();  // 构建过程的每一步
    void buildWall();
    void buildDoor();
    void buildDecoration();
    House getHouse();        // 返回不同的对象
}

class WoodenHouseBuilder implements HouseBuilder {
    private House house = new House();
    
    void buildFoundation() { house.setFoundation("木地基"); }
    void buildWall() { house.setWall("木墙"); }
    void buildDoor() { house.setDoor("木门窗"); }
    void buildDecoration() { house.setDecoration("豪华装修"); }
    House getHouse() { return house; }
}

class BrickHouseBuilder implements HouseBuilder {
    private House house = new House();
    
    void buildFoundation() { house.setFoundation("水泥地基"); }
    void buildWall() { house.setWall("砖墙"); }
    void buildDoor() { house.setDoor("铝合金门窗"); }
    void buildDecoration() { house.setDecoration("简装"); }
    House getHouse() { return house; }
}

// 使用
Director director = new Director();

director.setBuilder(new WoodenHouseBuilder());
House woodenHouse = director.construct();
// 输出:木地基 + 木墙 + 木门窗 + 豪华装修

director.setBuilder(new BrickHouseBuilder());
House brickHouse = director.construct();
// 输出:水泥地基 + 砖墙 + 铝合金门窗 + 简装

// 注意:输入相同(构建步骤),输出完全不同的 House 对象

3.4 关键区别总结

对比维度 策略模式 建造者模式
目的 封装可互换的算法 分离复杂对象的构建与表示
变化点 同一个操作的不同实现 构建过程的每一步
输出结果 相同类型,相同结果 不同类型的对象表示
组合方式 单一方法替换 多步骤组合
典型场景 排序、支付、导航 文档生成、UI 构建、SQL 构建

四、三种模式的本质区别

4.1 核心思想对比

复制代码
模板方法模式:
├── 核心思想:好莱坞原则(别调用我们,我们调用你)
├── 控制流:父类控制流程,子类填充细节
└── 类比:填空题(框架已定,填部分内容)

策略模式:
├── 核心思想:算法族的可互换性
├── 控制流:客户端选择策略,上下文执行
└── 类比:选择题(同一问题,不同解法)

建造者模式:
├── 核心思想:构建过程与表示分离
├── 控制流:指挥者控制步骤,建造者实现细节
└── 类比:组装模型(步骤固定,零件不同,成品不同)

4.2 一句话区分

模式 一句话理解
模板方法模式 流程固定,部分步骤可变 → 同一类产品的不同口味
策略模式 目标相同,算法可变 → 同一问题的不同解法
建造者模式 步骤固定,内容可变 → 相同流程的不同产物

4.3 类比理解

复制代码
烹饪类比:

模板方法模式:
├── 菜谱:炒青菜(洗菜→切菜→热油→炒菜→装盘)
── 变化:炒菠菜 vs 炒生菜(切法和火候不同)
└── 结果:都是炒青菜,只是口味略有不同

策略模式:
├── 目标:把菜做熟
├── 变化:炒 vs 煮 vs 蒸(烹饪方法不同)
└── 结果:菜都熟了,只是做法不同

建造者模式:
├── 流程:准备食材→烹饪→调味→装盘
├── 变化:中餐 vs 西餐 vs 日餐(每步都不同)
└── 结果:完全不同的菜品

五、常见理解误区

5.1 误区一:建造者模式类似模板方法模式

错误理解:建造者的构建过程类似模板方法模式,构建过程中根据对象的不同,最终输出的对象不同。

修正说明

维度 模板方法模式 建造者模式
变化范围 部分步骤不同 所有步骤都不同
输出结果 同一类型的不同变体 完全不同的对象表示
流程控制 抽象类中的模板方法 独立的 Director 类

关键区别:模板方法模式中,通常只有部分步骤是抽象的,其他步骤是固定的;而建造者模式中,每一步都可以完全不同。

5.2 误区二:对象不同类似于策略模式

错误理解:对象不同类似于策略模式,根据不同的需要选择不同的对象。

修正说明

维度 策略模式 建造者模式
输出结果 相同类型,相同结果 不同类型的对象表示
组合方式 单一方法替换 多步骤组合
目的 算法可互换 构建与表示分离

关键区别:策略模式是同一操作的不同算法,输出结果相同;建造者模式是构建过程相同,输出完全不同的对象。

5.3 更准确的理解

复制代码
建造者模式 = 固定流程 + 可变实现 + 不同产物

├── 固定流程:Director 控制的构建步骤顺序
├── 可变实现:每个 Builder 实现每一步的具体内容
└── 不同产物:不同 Builder 产生不同形态的对象

类比:
├── 模板方法:同一份菜谱,不同厨师微调某些步骤 → 同一道菜的不同口味
├── 策略模式:同一道数学题,不同解法 → 同一个答案
── 建造者模式:同一套组装步骤,不同零件 → 完全不同的产品

六、实际开发中的选择建议

6.1 模式选择决策树

markdown 复制代码
需要创建复杂对象?
├── 是 → 对象的构建步骤是否固定?
│       ├── 是 → 每一步的内容是否都不同?
│       │       ├── 是 → 使用建造者模式
│       │       └── 否 → 考虑模板方法模式
│       └── 否 → 考虑工厂模式或抽象工厂模式
└── 否 → 需要 interchangeable 的算法?
        ├── 是 → 使用策略模式
        └── 否 → 考虑其他模式

6.2 场景对照表

场景 推荐模式 原因
算法流程固定,部分步骤需要变化 模板方法模式 定义骨架,子类填充细节
同一操作有多种实现,需要动态切换 策略模式 算法可互换
复杂对象构建,构建步骤固定但内容不同 建造者模式 分离构建与表示
需要链式调用创建对象 建造者模式(变种) 流式 API
创建对象家族 抽象工厂模式 产品族概念
简单对象创建 工厂方法模式 单一产品

6.3 实际案例

java 复制代码
// 场景 1:文档生成(建造者模式)
// 构建步骤固定:标题→正文→页脚
// 但 PDF、HTML、Word 的每一步实现都不同
// → 使用建造者模式

// 场景 2:数据校验(策略模式)
// 目标:验证数据是否合法
// 不同规则:邮箱校验、手机号校验、身份证校验
// → 使用策略模式

// 场景 3:报表生成(模板方法模式)
// 流程固定:查询数据→格式化→生成报表→发送邮件
// 但不同报表的查询和格式化步骤不同
// → 使用模板方法模式

七、总结

7.1 核心要点回顾

概念 要点
构建 组装对象的步骤和过程(怎么做)
表示 最终生成的对象形态(做什么)
分离 构建过程固定不变,通过更换 Builder 产生不同表示
精髓 客户端只需知道"构建什么",不需关心"怎么构建"

7.2 三种模式一句话总结

复制代码
模板方法模式:流程固定,部分步骤可变 → 同一类产品的不同口味
策略模式:目标相同,算法可变 → 同一问题的不同解法
建造者模式:步骤固定,内容可变 → 相同流程的不同产物

7.3 学习建议

  1. 理解核心概念:先理解"构建"与"表示"的含义
  2. 对比学习:将建造者模式与模板方法、策略模式对比学习
  3. 代码实践:手写三种模式的代码,体会差异
  4. 场景应用:在实际项目中识别适用场景

文档版本:v1.0 最后更新:2026-05-26

相关推荐
武子康37 分钟前
Java-07 深入浅出 MyBatis数据库一对多关系模型实战:表结构设计与查询实现
java·后端
花椒技术1 小时前
企业内部 Agent 落地复盘:Gateway、Skill 和二次确认如何串起受控业务执行
后端·agent·ai编程
我是一颗柠檬3 小时前
【MySQL全面教学】MySQL事务与ACID Day9(2026年)
数据库·后端·mysql
枕星而眠3 小时前
数据结构八大排序详解(一):四大简单排序
c语言·数据结构·c++·后端
IT_陈寒3 小时前
React useEffect闭包陷阱差点把我整失业了
前端·人工智能·后端
苍何4 小时前
爆肝两周,我把 Codex 最全实战指南开源了
后端
bug菌4 小时前
【SpringBoot 3.x 第254节】夯爆了,数据库访问性能优化实战详解!
数据库·spring boot·后端
Rust研习社5 小时前
从碎片化到标准化:cargo-bp 如何重构 Rust 开发逻辑
后端·rust·编程语言
锋行天下5 小时前
一句mysql复杂查询搞崩一个壮汉
后端·mysql·go
sinat_255487815 小时前
IDEA:查找文件/类
java·ide·设计模式·intellij-idea