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

引言

模板方法模式(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 示例

假设实现饮料冲泡流程。

类实现

// 抽象类 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(),不改整体结构。

函数式实现

// ====================== // 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

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

@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

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

@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

 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

export class ProductImportStrategy extends AbstractBatchJobStrategy {   protected async preProcessBatchJob(job) { ... }   protected async processJob(job) { ... }   protected async postProcessBatchJob(job) { ... } } 
  • 基类定义“批处理任务生命周期流程”
  • 子类完成具体逻辑

结语

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

发表评论

评论已关闭。

相关文章