模板方法模式(Template Method Pattern)

简介: 模板方法模式是一种行为型设计模式,定义一个操作中的算法骨架,将某些步骤的实现延迟到子类。子类可以在不改变算法结构的情况下重新定义算法的某些步骤。适用于多个类有相似操作流程且部分步骤需要定制的场景。优点包括高复用性、扩展性强和清晰明确;缺点是灵活性降低和可能引入性能开销。示例包括文件解析和策略模式的对比。

模板方法模式(Template Method Pattern)详解

1. 定义

模板方法模式是一种行为型设计模式,定义一个操作中的算法骨架,将某些步骤的实现延迟到子类。通过模板方法,子类可以在不改变算法结构的情况下重新定义算法的某些步骤。

通俗解释:

模板方法就像烹饪中的食谱,它定义了做菜的步骤(算法骨架),而每道菜的具体细节(比如调味方式)由厨师(子类)决定。这样既保证了流程的一致性,又允许定制化。


2. 使用场景

使用场景 描述
算法框架一致,细节可变 比如不同类型的文件解析:整体流程相同,但具体解析逻辑因文件类型不同而不同。
避免重复代码 公共逻辑上移到父类,实现代码复用,具体逻辑留给子类实现。
确保算法框架不被修改 算法骨架在父类中定义,不允许被改变,而只开放局部步骤供子类扩展。

3. 模板方法模式的优缺点

特性 模板方法模式 策略模式
优点 复用性高:提取通用逻辑,避免重复代码。
扩展性强:子类只需实现定制化步骤。
清晰明确:明确了算法的执行顺序,逻辑更清楚。
灵活性高:可以在运行时动态替换算法或行为。
扩展性强:通过新增策略类来扩展新的算法或行为,无需修改原有代码。
遵循开闭原则:对扩展开放,对修改封闭。
缺点 灵活性降低:父类定义的算法框架限制了子类的自由度。
继承问题:容易导致子类层次结构过于复杂。
违反开闭原则:算法框架一旦定义,修改困难。
可能的性能开销:在某些情况下,策略模式可能引入额外的性能开销,因为需要在运行时决定使用哪个策略。
客户端代码复杂性:客户端可能需要了解所有策略的细节,以便在适当的时机选择和使用它们。

4. 模板方法模式的组成

  1. 抽象类
    定义算法的骨架(模板方法)和必要的抽象方法。
  2. 具体子类
    实现抽象类中的具体步骤,定制行为。
  3. 模板方法
    在抽象类中定义,通常是 final 的,不允许子类修改。

5. 示例:文件解析

示例描述:

不同类型的文件(比如 JSON 和 XML)解析逻辑大致相同:

  1. 打开文件。
  2. 读取内容。
  3. 解析数据。
  4. 关闭文件。

其中,解析数据的细节因文件类型不同而不同。


C++ 示例

#include <iostream>
#include <string>
using namespace std;

// 抽象类:文件解析器
class FileParser {
public:
   // 模板方法,定义解析流程
   void parseFile(const string& fileName) {
       openFile(fileName);
       readFile();
       parseData();  // 留给子类实现
       closeFile();
   }

   virtual ~FileParser() = default;

protected:
   void openFile(const string& fileName) {
       cout << "Opening file: " << fileName << endl;
   }

   void readFile() {
       cout << "Reading file content..." << endl;
   }

   virtual void parseData() = 0;  // 抽象方法,子类实现

   void closeFile() {
       cout << "Closing file." << endl;
   }
};

// 具体子类:JSON文件解析器
class JSONParser : public FileParser {
protected:
   void parseData() override {
       cout << "Parsing JSON data." << endl;
   }
};

// 具体子类:XML文件解析器
class XMLParser : public FileParser {
protected:
   void parseData() override {
       cout << "Parsing XML data." << endl;
   }
};

// 客户端代码
int main() {
   FileParser* parser = new JSONParser();
   parser->parseFile("data.json");
   delete parser;

   parser = new XMLParser();
   parser->parseFile("data.xml");
   delete parser;

   return 0;
}


C# 示例

using System;

// 抽象类:文件解析器
public abstract class FileParser {
   // 模板方法
   public void ParseFile(string fileName) {
       OpenFile(fileName);
       ReadFile();
       ParseData(); // 留给子类实现
       CloseFile();
   }

   protected void OpenFile(string fileName) {
       Console.WriteLine($"Opening file: {fileName}");
   }

   protected void ReadFile() {
       Console.WriteLine("Reading file content...");
   }

   protected abstract void ParseData(); // 抽象方法

   protected void CloseFile() {
       Console.WriteLine("Closing file.");
   }
}

// 具体子类:JSON文件解析器
public class JSONParser : FileParser {
   protected override void ParseData() {
       Console.WriteLine("Parsing JSON data.");
   }
}

// 具体子类:XML文件解析器
public class XMLParser : FileParser {
   protected override void ParseData() {
       Console.WriteLine("Parsing XML data.");
   }
}

// 客户端代码
class Program {
   static void Main() {
       FileParser parser = new JSONParser();
       parser.ParseFile("data.json");

       parser = new XMLParser();
       parser.ParseFile("data.xml");
   }
}


模板方法模式的类图

6. 模板方法模式的扩展

钩子方法(Hook Method)

模板方法模式中可以包含钩子方法,子类可以通过覆盖钩子方法来影响模板方法的行为,但不是必须实现的。这种方法进一步增强了模式的灵活性。


7. 模板方法模式与其他模式对比

特性 模板方法模式 策略模式
核心作用 固定算法流程,允许部分步骤定制 动态替换算法或行为
子类角色 扩展部分算法步骤 提供具体算法实现
抽象层次 抽象类和子类 接口和实现类
场景适用 算法逻辑固定但有定制需求 需要灵活切换算法或行为

模板方法模式总结

  1. 适用范围:当多个类具有相似的操作流程,且部分步骤需要定制时,使用模板方法模式非常合适。
  2. 设计哲学:使用“模板”将不变的部分抽象出来,同时开放定制点以支持扩展。
  3. 注意事项:避免过多的抽象和继承层次,防止代码复杂化。
相关文章
企业微信接入系列-自建应用
本文主要介绍在接入企业微信时,需要自建应用,以及应用的配置
企业微信接入系列-自建应用
|
6月前
|
人工智能 测试技术 API
从工具到伙伴:一文看懂 AI Agent 与 Agentic AI 的核心差异
AI Agent是执行者,按指令调用工具;Agentic AI是决策者,能自主规划、反思优化。二者核心差异在于是否具备主动决策与自我驱动能力,将重塑智能测试未来。
|
8月前
|
负载均衡 监控 Java
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
本文详细介绍了 Spring Cloud Gateway 的核心功能与实践配置。首先讲解了网关模块的创建流程,包括依赖引入(gateway、nacos 服务发现、负载均衡)、端口与服务发现配置,以及路由规则的设置(需注意路径前缀重复与优先级 order)。接着深入解析路由断言,涵盖 After、Before、Path 等 12 种内置断言的参数、作用及配置示例,并说明了自定义断言的实现方法。随后重点阐述过滤器机制,区分路由过滤器(如 AddRequestHeader、RewritePath、RequestRateLimiter 等)与全局过滤器的作用范围与配置方式,提
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
|
前端开发 JavaScript 数据格式
图片URL转file文件(前端+后端node.js)
图片URL转file文件(前端+后端node.js)
|
Arthas Kubernetes 数据可视化
推荐10个GitHub上适合练手的后端项目(涵盖初中高阶)
上周,我们推出了26个好玩又有挑战的前端练习项目。 不少同学留言说,那后端的呢?后端也要! 淘系工程师一呼就应,我们邀请了2位淘系技术后端工程师,筛选出10个难度层层递进,好玩且实用的后端项目,包含java类库中的“瑞士军刀”工具、可视化API展现等等,难度依然分为【初级篇:4个】、【中级篇:3个】、【高级篇:3个】,不同学习诉求的同学可按需选择~
推荐10个GitHub上适合练手的后端项目(涵盖初中高阶)
|
供应链 前端开发 JavaScript
《Solidity 简易速速上手小册》第10章:区块链项目实战(2024 最新版)(上)
《Solidity 简易速速上手小册》第10章:区块链项目实战(2024 最新版)
667 0
|
6月前
|
存储 人工智能 算法
构建AI智能体:十五、超越关键词搜索:向量数据库如何解锁语义理解新纪元
向量数据库是专为存储和检索高维向量设计的新型数据库,通过Embedding技术将文本、图像等非结构化数据转化为向量,利用近似最近邻(ANN)算法实现语义级相似性搜索,广泛应用于AI推荐、语义搜索与智能问答,是大模型时代的关键基础设施。
773 12
|
Java 开发者 Spring
【SpringBoot 异步魔法】@Async 注解:揭秘 SpringBoot 中异步方法的终极奥秘!
【8月更文挑战第25天】异步编程对于提升软件应用的性能至关重要,尤其是在高并发环境下。Spring Boot 通过 `@Async` 注解简化了异步方法的实现。本文详细介绍了 `@Async` 的基本用法及配置步骤,并提供了示例代码展示如何在 Spring Boot 项目中创建与管理异步任务,包括自定义线程池、使用 `CompletableFuture` 处理结果及异常情况,帮助开发者更好地理解和运用这一关键特性。
2721 1
|
Kubernetes 调度 虚拟化
Kubernetes和Docker有什么区别
【10月更文挑战第18天】Kubernetes和Docker有什么区别
|
Web App开发 缓存 JavaScript
使用TypeScript创建高效HTTP代理请求
使用TypeScript创建高效HTTP代理请求