设计模式精讲 Day 22:模板方法模式(Template Method Pattern)

【设计模式精讲 Day 22】模板方法模式(Template Method Pattern)


文章标签

设计模式, 模板方法模式, Java开发, 面向对象设计, 软件架构, 设计模式实战, Java应用开发


文章简述

模板方法模式是一种行为型设计模式,它通过定义一个算法的骨架,并将某些步骤延迟到子类中实现。这种模式允许子类在不改变算法结构的前提下,重新定义算法的某些步骤,从而提高代码复用性和可扩展性。本文作为“设计模式精讲”系列的第22天,深入讲解了模板方法模式的核心思想、实现方式和实际应用场景。文章通过完整的Java代码示例,展示了如何在具体业务场景中使用模板方法模式优化系统结构,并结合真实案例分析其优势与局限性。无论你是初学者还是有经验的开发者,这篇文章都将帮助你掌握模板方法模式的设计精髓并应用于实际项目中。


【设计模式精讲 Day 22】模板方法模式(Template Method Pattern)

开篇:模板方法模式的核心思想与应用价值

今天是“设计模式精讲”系列的第22天,我们聚焦于模板方法模式(Template Method Pattern)。模板方法模式是一种行为型设计模式,它通过定义一个算法的骨架,并将某些步骤延迟到子类中实现,使得子类可以在不改变算法结构的前提下,重新定义算法的某些步骤。

在软件开发中,很多业务流程具有固定的执行顺序,但其中某些步骤可能因具体需求而变化。例如,支付流程通常包括验证、扣款、记录日志等步骤,但不同支付方式的具体实现可能不同。如果直接在同一个类中处理这些逻辑,会导致代码重复和难以维护。而模板方法模式通过将公共逻辑封装在父类中,将可变部分交给子类实现,实现了算法结构与具体实现的解耦。

本篇文章将从模式定义、结构、适用场景、实现方式、工作原理、优缺点分析、案例分析等多个维度,全面解析模板方法模式,并提供完整可运行的Java代码示例,帮助你真正掌握这一设计模式。


模式定义

1.1 正式定义

模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法的框架,并在该框架中调用一些抽象方法或钩子方法,由子类来实现这些方法。这样,算法的结构保持不变,但具体的实现可以由不同的子类进行定制。

1.2 核心思想

  • 算法骨架固定:算法的整体流程由父类定义。
  • 具体步骤延迟实现:部分步骤由子类实现,增强灵活性。
  • 复用性高:避免重复代码,提升代码复用性。
  • 符合开闭原则:对扩展开放,对修改关闭。

模式结构

2.1 UML 类图说明(文字描述)

模板方法模式包含以下几个关键角色:

角色说明
AbstractClass(抽象类)定义算法的骨架,包含模板方法和抽象方法。
ConcreteClass(具体类)实现抽象方法,完成算法的具体步骤。

2.2 示例结构说明

  • AbstractClass 中定义了一个 templateMethod() 方法,该方法调用了多个抽象方法(如 primitiveOperation1()primitiveOperation2() 等)。
  • ConcreteClassAConcreteClassB 分别实现这些抽象方法,提供不同的具体逻辑。

适用场景

场景说明
多个类有相似的算法流程当多个类需要按照相同流程执行操作时,适合使用模板方法模式。
算法的某些步骤可能变化如果算法中的某些步骤需要根据情况变化,适合将其封装为抽象方法。
提高代码复用性将公共逻辑放在父类中,减少重复代码。
控制算法的执行顺序保证算法的执行顺序一致,同时允许子类自定义部分步骤。

实现方式

3.1 Java 代码实现

以下是一个基于模板方法模式的简单示例,模拟一个“咖啡与茶的制作流程”。

3.1.1 抽象类
// Beverage.java
public abstract class Beverage {// 模板方法:定义算法的骨架public final void prepareRecipe() {boilWater();brew();pourInCup();addCondiments();}// 具体方法:所有子类共有的步骤private void boilWater() {System.out.println("煮水");}private void pourInCup() {System.out.println("倒入杯子");}// 抽象方法:子类需要实现的方法protected abstract void brew();// 钩子方法:可选实现protected boolean isCondimentRequired() {return true;}// 子类可以选择是否重写此方法protected void addCondiments() {if (isCondimentRequired()) {System.out.println("添加配料");}}
}
3.1.2 具体类
// Coffee.java
public class Coffee extends Beverage {@Overrideprotected void brew() {System.out.println("冲泡咖啡");}@Overrideprotected boolean isCondimentRequired() {return true; // 咖啡需要加糖}
}// Tea.java
public class Tea extends Beverage {@Overrideprotected void brew() {System.out.println("冲泡茶叶");}@Overrideprotected boolean isCondimentRequired() {return false; // 茶不需要加糖}
}
3.1.3 测试类
// TemplateMethodPatternTest.java
public class TemplateMethodPatternTest {public static void main(String[] args) {Beverage coffee = new Coffee();coffee.prepareRecipe();System.out.println("-----------");Beverage tea = new Tea();tea.prepareRecipe();}
}

输出:

煮水
冲泡咖啡
倒入杯子
添加配料
-----------
煮水
冲泡茶叶
倒入杯子

工作原理

模板方法模式通过将算法的通用逻辑封装在父类中,而将特定逻辑交由子类实现,从而实现算法结构与具体实现的分离。

  • 模板方法:定义算法的步骤,调用抽象方法或钩子方法。
  • 抽象方法:由子类实现,提供具体逻辑。
  • 钩子方法:提供默认实现,子类可以选择是否覆盖。

这种机制符合开闭原则,即对扩展开放,对修改关闭。同时,也符合单一职责原则,每个类只关注自己的职责。


优缺点分析

优点缺点
代码复用性强:公共逻辑集中管理,避免重复代码。增加类的数量:每个子类都需要继承抽象类。
提高可维护性:算法结构清晰,便于后期维护和扩展。灵活性有限:如果算法结构频繁变化,可能需要重构。
符合开闭原则:新增功能只需扩展子类,无需修改现有代码。过度依赖继承:可能导致类层次复杂。

案例分析:电商订单处理流程中的模板方法模式应用

4.1 问题描述

某电商平台的订单处理流程包括:校验订单、计算价格、生成发票、发送通知等步骤。不同类型的订单(如普通订单、促销订单、预售订单)在某些步骤上存在差异,如促销订单需要额外的折扣计算,预售订单需要库存预扣。

4.2 解决方案

采用模板方法模式重构订单处理流程,将通用逻辑放在父类中,将可变部分交给子类实现。

4.2.1 抽象类
// OrderProcessor.java
public abstract class OrderProcessor {// 模板方法public final void processOrder(Order order) {validate(order);calculatePrice(order);generateInvoice(order);sendNotification(order);}protected abstract void validate(Order order);protected abstract void calculatePrice(Order order);protected void generateInvoice(Order order) {System.out.println("生成发票");}protected void sendNotification(Order order) {System.out.println("发送通知");}
}
4.2.2 具体类
// NormalOrderProcessor.java
public class NormalOrderProcessor extends OrderProcessor {@Overrideprotected void validate(Order order) {System.out.println("验证普通订单");}@Overrideprotected void calculatePrice(Order order) {System.out.println("计算普通订单价格");}
}// PromotionOrderProcessor.java
public class PromotionOrderProcessor extends OrderProcessor {@Overrideprotected void validate(Order order) {System.out.println("验证促销订单");}@Overrideprotected void calculatePrice(Order order) {System.out.println("计算促销订单价格(含折扣)");}
}
4.2.3 使用示例
public class OrderProcessorTest {public static void main(String[] args) {Order order = new Order();OrderProcessor normalProcessor = new NormalOrderProcessor();normalProcessor.processOrder(order);System.out.println("----------");OrderProcessor promotionProcessor = new PromotionOrderProcessor();promotionProcessor.processOrder(order);}
}

输出:

验证普通订单
计算普通订单价格
生成发票
发送通知
----------
验证促销订单
计算促销订单价格(含折扣)
生成发票
发送通知

与其他模式的关系

模式关系说明
策略模式(Strategy Pattern)相似但用途不同策略模式封装算法,模板方法模式封装算法骨架
工厂模式(Factory Pattern)可组合使用工厂模式用于创建对象,模板方法模式用于定义算法结构
命令模式(Command Pattern)不同但可结合使用命令模式封装请求,模板方法模式控制算法流程

总结

5.1 本日学习要点

  • 模板方法模式的核心思想是将算法的骨架定义在父类中,将具体步骤延迟到子类中实现。
  • 通过模板方法,可以统一算法的执行流程,同时允许子类灵活调整部分步骤。
  • 模板方法模式适用于具有固定流程但部分步骤需定制的场景。
  • 通过完整 Java 示例,展示了模板方法模式的实现方式和实际应用。
  • 模板方法模式与策略模式、工厂模式等存在相似之处,但在应用场景上有明显区别。

5.2 下一日预告

明天我们将进入“设计模式精讲”系列的第23天,主题为【设计模式精讲 Day 23】访问者模式(Visitor Pattern)。我们将探讨如何通过访问者模式实现对对象结构的遍历与操作,提升系统的灵活性和可扩展性。敬请期待!


进一步学习资料

  1. 《设计模式:可复用面向对象软件的基础》 —— GoF 经典著作
  2. 模板方法模式 - Wikipedia
  3. Java 设计模式之模板方法模式详解
  4. Spring 框架中的模板方法模式应用
  5. 模板方法模式 vs 策略模式对比

【设计模式精讲 Day 22】模板方法模式(Template Method Pattern) 已完成,欢迎转发、收藏、评论交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/912649.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/912649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何在pytorch中使用tqdm:优雅实现训练进度监控

文章目录 为什么需要进度条?tqdm 简介基础用法示例深度学习中的实战应用1. 数据加载进度监控2. 训练循环增强版3. 验证阶段集成 高级技巧与最佳实践1. 自定义进度条样式2. 嵌套进度条(多任务)3. 分布式训练支持4. 与日志系统集成 性能优化建议…

Linux中的xxd命令详解

xxd 是一个 十六进制转储(hex dump)工具,通常用于将二进制文件转换为十六进制格式,或者反向转换(十六进制→二进制)。它是 vim 的一部分,但在大多数 Linux 系统(如 Ubuntu&#xff0…

磐维数据库panweidb3.1.0单节点多实例安装

0 说明 业务科室提单需要在某台主机上部署多个单机磐维数据库,用于业务测试。以下内容展示如何在单节点安装多个磐维数据库实例。 1 部署环境准备 1.1 IP 地址及端口 instipport实例1192.168.131.1717700实例2192.168.131.1727700 在131.17上分别安装两个实例&…

转录组分析流程(三):功能富集分析

我们的教程主要是以一个具体的例子作为线索,通过对公共数据库数据bulk-RNA-seq的挖掘,利用生物信息学分析来探索目标基因集作为某种疾病数据预后基因的潜能及其潜在分子机制,同时在单细胞水平分析(对scRNA-seq进行挖掘)预后基因的表达,了解细胞之间的通讯网络,以期为该疾病…

全面掌握 tkinter:Python GUI 编程的入门与实战指南

在自动化、工具开发、数据可视化等领域,图形用户界面(GUI)往往是提升用户体验的重要方式。作为 Python 官方内置的 GUI 库,tkinter 以其轻量、跨平台、易于学习的特性成为初学者和轻量级应用开发者首选。 本文将以深入浅出的方式…

TDH社区开发版安装教程

(注:本文章来源于星环官网安装手册) 后面放置了视频和安装手册连接 1、硬件及环境要求 Docker17及以上版本,支持Centos,Ubuntu等系统(注:这里我使用CentOS-7版本,最佳版本推荐为7.…

Linux基本命令篇 —— grep命令

grep是Linux/Unix系统中一个非常强大的文本搜索工具,它的名字来源于"Global Regular Expression Print"(全局正则表达式打印)。grep命令用于在文件中搜索包含特定模式的行,并将匹配的行打印出来。 目录 一、基本语法 二…

苍穹外卖问题系列之 苍穹外卖订单详情前端界面和网课给的不一样

问题 如图,我的前端界面和网课里面给的不一样,没有“申请退款”和一些其他的该有的东西。 原因分析 “合计”这一栏显示undefined说明我们的总金额没有输入进去。可以看看订单提交那块的代码,是否可以正确输出。还有就是订单详细界面展示这…

CppCon 2018 学习:EMULATING THE NINTENDO 3DS

我们来逐个分析一下这个 组件交互模型 和 仿真 & 序列化 的关系,特别是主线程(Main Thread)与其他系统组件之间的交互。 1. Main Thread — simple (basically memcpy) --> GPU Main Thread(主线程)负责游戏的…

[Python 基础课程]数字

数字 数字数据类型用于存储数值,比如整数、小数等。数据类型是不允许改变的,这就意味着如果改变数字数据类型的值,将重新分配内存空间。 创建数字类型的变量: var1 1 var2 10创建完变量后,如果想废弃掉这个变量&a…

Linux CentOS环境下Java连接MySQL数据库指南

文章目录 前言一、环境准备1.1 系统更新1.2 Java环境安装1.3 MySQL数据库安装1.4 下载JDBC驱动 二、编写Java程序2.1 代码如下2.2 编译和运行2.3 验证创建结果 三、代码上传至Gitee3.1 安装配置Git3.2 克隆仓库到本地3.3 添加Java项目文件3.4 提交代码到本地仓库3.5 推送到Gite…

LLM面试12

讯飞算法工程师面试题 SVM核函数能否映射到无穷维 可以的,多项式核函数将低维数据映射到高维(维度是有限的),而高斯核函数可以映射到无穷维。由 描述下xgb原理,损失函数 首先需要说一说GBDT,它是一种基于boosting增强…

类加载生命周期与内存区域详解

类加载生命周期与内存区域详解 Java 类加载的生命周期包括加载、验证、准备、解析、初始化五个阶段,每个阶段在内存中的存储区域和赋值机制各有不同。以下是详细解析: 一、类加载生命周期阶段 1. 加载(Loading) 内存区域&…

正交视图三维重建2 笔记 2d线到3d线2 先生成3d线然后判断3d线在不在

应该先连线再判断线在不在 if(fx1tx1&&tx1tx2){ const A[fx1, fy1, ty1];const Ahat[fx1, fy1, ty2];drawlines(A[0], A[1], A[2], Ahat[0], Ahat[1], Ahat[2], lineId, type,2);}if(fx2tx1&&tx1tx2){ const B[fx2, fy2, ty1];const Bhat[fx2, fy2, ty2];drawl…

Hibernate对象生命周期全解析

Hibernate对象生命周期详解 Hibernate作为Java领域主流的ORM框架,其核心机制之一就是对持久化对象生命周期的管理。理解Hibernate对象生命周期对于正确使用Hibernate进行数据持久化操作至关重要。Hibernate将对象分为三种主要状态:瞬时态(Transient)、持久态(Persistent)和游…

MCP 协议使用核心讲解

📄 MCP 协议使用核心讲解 ✅ MCP 协议的核心在于以下几个方面 一、MCP 请求结构(MCPRequest) {"messages": [{"role": "user","content": "帮我查询一下上海的天气"}],"tools"…

云计算中的几何方法:曲面变形的可视化与动画-AI云计算数值分析和代码验证

着重强调微分方程底层的几何和代数结构,以进行更深入的分析和求解方法。开发结构保持的数值方法,以在计算中保持定性特征。统一符号和数值方法,实现有效的数学建模。利用几何解释(如双曲几何)求解经典微分方程。利用计…

OpenCV篇——项目(一)OCR识别读取银行卡号码

目录 信用卡数字识别系统:前言与代码解析 前言 项目代码 ​​​​​​结果演示 代码模块解析 1. 参数解析模块 2. 轮廓排序函数 3. 图像预处理模块 4. 输入图像处理流程 5. 卡号区域定位 6. 数字识别与输出 系统优势 信用卡数字识别系统:前言…

Adobe AI高效设计秘籍与创新思维进阶

开篇:十年设计征途,Adobe赋能创意飞翔 作为一名在设计领域耕耘十年的旅居职业设计师,我得益于英国帕维斯经济与音乐学院(Parvis School of Economics and Music)提供的Adobe正版教育订阅,得以持续探索技术…

vc formal实例

命令: module load gui 方式启动命令, 看一下cc_pinmux.tcl 里面有什么: 工具feature 的设置,不太懂 对特定模块做blackbox, library file, 一般是工具无法识别的模块,例如 IO lib,memory lib,analog lib, 内部有 …