常用设计模式:模板方法模式

引言

模板方法模式(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) { ... }
}
  • 基类定义"批处理任务生命周期流程"
  • 子类完成具体逻辑

结语

模板方法模式提升代码可维护性,适用于框架设计。

相关推荐
Lei_3359675 小时前
[設計模式]二十三種設計模式
设计模式
吃饺子不吃馅6 小时前
面试官:JWT、Cookie、Session、Token有什么区别?
前端·设计模式·面试
leafff1237 小时前
一文读懂:如何选择适合的RAG系统架构设计模式?
设计模式·自然语言处理·系统架构
ZHE|张恒9 小时前
设计模式实战篇(一):彻底搞懂 Singleton 单例模式
单例模式·设计模式
喝拿铁写前端1 天前
从面条代码到抽象能力:一个小表单场景里的前端成长四阶段
前端·设计模式·架构
依米_1 天前
一文带你剖析 Promise.then all 实现原理,状态机、发布订阅模式完美实现异步编程
javascript·设计模式
jzhwolp1 天前
从基本链表到侵入式链表,体会内核设计思路
c语言·后端·设计模式
李宥小哥1 天前
结构型设计模式1
设计模式
lapiii3581 天前
[智能体设计模式] 第五章 :函数调用
microsoft·设计模式