引言
模板方法模式(Template Method Pattern)是一种行为型设计模式。它定义算法骨架,将具体步骤延迟到子类实现。适用于固定流程但部分步骤可变的情景,如游戏初始化或数据处理。
定义
- 抽象类:定义模板方法(final方法)和抽象步骤。
- 具体子类:实现抽象步骤。
优点:代码复用,易扩展。缺点:子类过多时复杂。
classDiagram class Beverage { +prepare(): void +boilWater(): void +pourInCup(): void +brew(): void abstract +addCondiments(): void abstract } class Coffee { +brew(): void +addCondiments(): void } class Tea { +brew(): void +addCondiments(): void } Beverage <|-- Coffee Beverage <|-- Tea
TypeScript 示例
假设实现饮料冲泡流程。
类实现
typescript
// 抽象类
abstract class Beverage {
// 模板方法
prepare(): void {
this.boilWater();
this.brew();
this.pourInCup();
this.addCondiments();
}
boilWater(): void {
console.log("煮沸水");
}
abstract brew(): void; // 抽象步骤
pourInCup(): void {
console.log("倒入杯中");
}
abstract addCondiments(): void; // 抽象步骤
}
// 具体子类:咖啡
class Coffee extends Beverage {
brew(): void {
console.log("冲泡咖啡");
}
addCondiments(): void {
console.log("加糖和奶");
}
}
// 具体子类:茶
class Tea extends Beverage {
brew(): void {
console.log("浸泡茶叶");
}
addCondiments(): void {
console.log("加柠檬");
}
}
// 使用
const coffee = new Coffee();
coffee.prepare(); // 输出:煮沸水 冲泡咖啡 倒入杯中 加糖和奶
const tea = new Tea();
tea.prepare(); // 输出:煮沸水 浸泡茶叶 倒入杯中 加柠檬
prepare() 是模板方法,固定流程。子类重写 brew() 和 addCondiments(),不改整体结构。
函数式实现
typescript
// ======================
// Step 1: 定义策略函数类型
// ======================
type BrewFunction = () => void;
type AddCondimentsFunction = () => void;
// ======================
// Step 2: 固定步骤函数
// ======================
const boilWater = (): void => {
console.log("🔥 Boiling water...");
};
const pourInCup = (): void => {
console.log("🥛 Pouring into cup...");
};
// ======================
// Step 3: 模板方法(高阶函数)
// ======================
const makeDrink =
(brew: BrewFunction, addCondiments: AddCondimentsFunction) =>
(): void => {
console.log("\n🧪 Starting to make a drink...\n");
boilWater(); // 固定
brew(); // 可变
pourInCup(); // 固定
addCondiments(); // 可变
console.log("\n✅ Drink is ready!\n");
};
// ======================
// Step 4: 策略实现(不同饮料)
// ======================
// Coffee
const brewCoffee: BrewFunction = () => {
console.log("☕ Brewing coffee grounds...");
};
const addSugarAndMilk: AddCondimentsFunction = () => {
console.log("🍬 Adding sugar and milk...");
};
// Tea
const brewTea: BrewFunction = () => {
console.log("🍵 Steeping the tea...");
};
const addLemon: AddCondimentsFunction = () => {
console.log("🍋 Adding a slice of lemon...");
};
// ======================
// Step 5: 组合并执行
// ======================
const makeCoffee = makeDrink(brewCoffee, addSugarAndMilk);
makeCoffee();
const makeTea = makeDrink(brewTea, addLemon);
makeTea();
真实案例
下面列举了 3 个真实开源仓库,包含明确的"模板方法模式(Template Method Pattern)"逻辑。
Apache Kafka(Java)
Kafka 的 复制(Replica / Fetcher / LogCleaner)流程大量使用模板方法模式。
模板方法骨架,文件:AbstractFetcherThread.java
java
public abstract class AbstractFetcherThread extends ShutdownableThread {
@Override
public void doWork() {
Map<TopicPartition, FetchData> fetched = fetchData(); // 模板步骤
processFetchedData(fetched); // 模板步骤
maybeThrottle();
}
protected abstract Map<TopicPartition, FetchData> fetchData();
protected abstract void processFetchedData(Map<TopicPartition, FetchData> fetched);
}
子类实现步骤,示例:ReplicaFetcherThread.java
java
@Override
protected Map<TopicPartition, FetchData> fetchData() {
// 从 leader 拉取日志
}
@Override
protected void processFetchedData(Map<TopicPartition, FetchData> fetched) {
// 写入本地日志副本
}
- doWork() 是固定流程(骨架)
- fetchData()、processFetchedData() 由子类决定
Spring Framework / Spring AOP
Spring AOP 的拦截器链实现中大量使用模板方法结构。
模板方法骨架,文件:AbstractPlatformTransactionManager.java
java
public final TransactionStatus getTransaction(TransactionDefinition definition) {
Object transaction = doGetTransaction(); // 模板步骤
boolean newTx = shouldStartTransaction(...);
if (newTx) {
doBegin(transaction, definition); // 模板步骤
}
return prepareTransactionStatus(...);
}
protected abstract Object doGetTransaction();
protected abstract void doBegin(Object transaction, TransactionDefinition definition);
子类实现步骤,示例:DataSourceTransactionManager.java
java
@Override
protected Object doGetTransaction() {
return new DataSourceTransactionObject();
}
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
// 开启 JDBC 事务
}
getTransaction()定义统一事务开启流程- 某些步骤由子类实现(JDBC, JPA, Hibernate 都不一样)
Medusa.js
Medusa 是一个基于 TypeScript 的电商框架,批量任务、支付、库存策略等通过抽象基类强制子类实现步骤。
模板方法骨架,文件:AbstractBatchJobStrategy.ts
typescript
export abstract class AbstractBatchJobStrategy {
async prepareBatchJob(batchJob: BatchJob): Promise<void> {
await this.preProcessBatchJob(batchJob); // 模板步骤
await this.processJob(batchJob); // 模板步骤
await this.postProcessBatchJob(batchJob); // 模板步骤
}
protected abstract preProcessBatchJob(job: BatchJob): Promise<void>;
protected abstract processJob(job: BatchJob): Promise<void>;
protected abstract postProcessBatchJob(job: BatchJob): Promise<void>;
}
子类实现步骤,示例:ProductImportStrategy.ts
typescript
export class ProductImportStrategy extends AbstractBatchJobStrategy {
protected async preProcessBatchJob(job) { ... }
protected async processJob(job) { ... }
protected async postProcessBatchJob(job) { ... }
}
- 基类定义"批处理任务生命周期流程"
- 子类完成具体逻辑
结语
模板方法模式提升代码可维护性,适用于框架设计。