摘要

模版方法设计模式是一种行为型设计模式,定义了算法的步骤顺序和整体结构,将某些步骤的具体实现延迟到子类中。它通过抽象类定义模板方法,子类实现抽象步骤,实现代码复用和算法流程控制。该模式适用于有固定流程但部分步骤可变的场景,如业务流程控制等。

1. 模版设计模式定义

定义一个操作中的算法骨架(即步骤的顺序和整体结构),而将某些步骤的具体实现延迟到子类中。子类可以在不改变算法结构的前提下,重新定义算法中的某些具体步骤。

1.1.1. 模版设计模式的关键点

  • 抽象模版类:定义一个模板方法,描述算法的整体流程。模板方法一般是 final,防止子类改变算法结构。
  • 基本方法(基本操作):模板方法所依赖的步骤,这些步骤可以是抽象的,也可以有默认实现。
  • 具体子类:实现抽象类中的抽象步骤,完成具体的业务逻辑。

1.1.2. 作用

  • 复用代码:把不变的行为放在父类,变化的行为由子类实现,避免代码重复。
  • 控制算法流程:子类只需关注具体步骤实现,算法整体流程由父类控制,增强代码的可维护性和可扩展性。

2. 模版设计模式结构

  1. 抽象类 (Abstract­Class) 会声明作为算法步骤的方法, 以及依次调用它们的实际模板方法。 算法步骤可以被声明为 抽象类型, 也可以提供一些默认实现。
  2. 具体类 (Concrete­Class) 可以重写所有步骤, 但不能重写模板方法自身。

2.1. 模版设计模式类图

2.2. 模版设计模式时序图

3. 模版设计模式实现方式

3.1. 模版设计模式的实现方式核心在于:

  • 在抽象父类中定义一个模板方法(通常是final的),它规定了算法的执行顺序和骨架。
  • 模板方法调用若干个基本方法(步骤),其中部分基本方法是抽象的,由子类实现;部分基本方法可以有默认实现。
  • 子类继承抽象父类,实现抽象步骤,完成具体业务逻辑。

3.2. 模板设计模式实现步骤

  1. 创建抽象类(AbstractClass)
    • 定义模板方法templateMethod(),并用final修饰,防止子类重写改变流程。
    • 模板方法中按照固定步骤顺序调用基本操作。
    • 定义基本操作(抽象方法或具体方法),其中抽象方法由子类实现。
  1. 创建具体子类(ConcreteClass)
    • 继承抽象类,实现抽象的基本方法,完成具体业务。

3.3. 示例代码(Java)

// 抽象模板类
public abstract class AbstractTemplate {// 模板方法,定义固定流程,防止子类覆盖public final void templateMethod() {step1();step2();step3();}// 抽象基本操作,由子类实现protected abstract void step1();protected abstract void step2();// 具体基本操作,父类实现,子类可选择复写protected void step3() {System.out.println("默认实现步骤3");}
}// 具体子类A
public class ConcreteTemplateA extends AbstractTemplate {@Overrideprotected void step1() {System.out.println("ConcreteTemplateA 实现步骤1");}@Overrideprotected void step2() {System.out.println("ConcreteTemplateA 实现步骤2");}
}// 具体子类B
public class ConcreteTemplateB extends AbstractTemplate {@Overrideprotected void step1() {System.out.println("ConcreteTemplateB 实现步骤1");}@Overrideprotected void step2() {System.out.println("ConcreteTemplateB 实现步骤2");}// 可以覆盖父类默认实现@Overrideprotected void step3() {System.out.println("ConcreteTemplateB 重写步骤3");}
}

3.4. 模版模式示例

public class Client {public static void main(String[] args) {AbstractTemplate templateA = new ConcreteTemplateA();templateA.templateMethod();// 输出:// ConcreteTemplateA 实现步骤1// ConcreteTemplateA 实现步骤2// 默认实现步骤3AbstractTemplate templateB = new ConcreteTemplateB();templateB.templateMethod();// 输出:// ConcreteTemplateB 实现步骤1// ConcreteTemplateB 实现步骤2// ConcreteTemplateB 重写步骤3}
}

说明

  • 模板方法templateMethod()固定了整体流程,子类不能改变流程,只能重写步骤细节。
  • 这样保证了算法骨架不变,细节可变。

4. 模版设计模式适合场景

4.1. ✅ 适合使用模版设计模式的场景

场景

说明

多个子类有相同算法骨架

多个子类共享固定流程,只有具体步骤实现不同,便于代码复用和规范流程。

需要复用公共流程代码

将不变的算法结构封装在父类,避免重复代码,提升维护性。

需要统一控制算法执行顺序

模板方法定义执行顺序,防止子类随意改变流程,保证算法正确执行。

算法结构清晰、变化点集中

业务流程稳定,只有个别步骤需要子类实现,方便集中管理和扩展。

希望固定流程,允许步骤扩展

允许子类通过实现抽象步骤或覆盖钩子方法灵活扩展功能,而不破坏整体流程。

4.2. ❌ 不适合使用模版设计模式的场景

场景

原因

需要动态调整或拼装流程

模板方法流程固定,难以支持运行时动态改变步骤或流程组合。

继承层次过深,代码复杂

模板方法依赖继承,过多层次会导致系统复杂且难维护。

业务变化点不明显或过少

过度抽象导致代码冗余,简单业务用模版模式反而增加复杂度。

多维度变化且复杂

多个变化点分布在算法不同部分,模板方法难以灵活应对,策略模式或责任链模式更合适。

需要高度灵活、组合式的行为

模板方法结构静态,不适合高动态组合或插件式设计。

5. 模版设计模式实战示例

5.1. 场景描述

在金融风控中,不同风控策略的执行流程大致相同:

  1. 数据准备
  2. 规则校验
  3. 风控决策(通过/拒绝)
  4. 结果记录

不同风控策略的规则校验细节不同,适合用模板设计模式抽象固定流程,把校验逻辑由子类实现。

5.2. 项目结构示例(Spring Boot)

com.example.riskcontrol
├── RiskControlTemplate.java      // 抽象模板类
├── UserRiskControl.java          // 具体风控策略1
├── TransactionRiskControl.java   // 具体风控策略2
├── RiskControlService.java       // 调用客户端
└── SpringBootApplication.java    // 启动类

5.3. 抽象模板类 RiskControlTemplate

package com.example.riskcontrol;public abstract class RiskControlTemplate {// 模板方法,定义风控流程public final void executeRiskControl(String userId) {prepareData(userId);boolean passed = validateRules(userId);makeDecision(passed);recordResult(userId, passed);}// 准备数据,具体实现可重写,默认空实现protected void prepareData(String userId) {System.out.println("准备风控数据,用户ID:" + userId);}// 抽象规则校验步骤,由具体策略实现protected abstract boolean validateRules(String userId);// 风控决策步骤,固定流程private void makeDecision(boolean passed) {if (passed) {System.out.println("风控通过,继续后续流程");} else {System.out.println("风控拒绝,终止流程");}}// 记录风控结果,默认实现protected void recordResult(String userId, boolean passed) {System.out.println("记录风控结果,用户ID:" + userId + ", 结果:" + (passed ? "通过" : "拒绝"));}
}

5.4. 具体策略实现类

package com.example.riskcontrol;import org.springframework.stereotype.Component;@Component("userRiskControl")
public class UserRiskControl extends RiskControlTemplate {@Overrideprotected boolean validateRules(String userId) {System.out.println("执行用户维度的风控规则校验,用户ID:" + userId);// 简单示例,实际接入数据库或外部接口判断return userId.hashCode() % 2 == 0;  // 偶数通过,奇数拒绝}
}
package com.example.riskcontrol;import org.springframework.stereotype.Component;@Component("transactionRiskControl")
public class TransactionRiskControl extends RiskControlTemplate {@Overrideprotected boolean validateRules(String userId) {System.out.println("执行交易维度的风控规则校验,用户ID:" + userId);// 这里模拟判断交易风险return userId.length() > 5;  // 用户ID长度大于5通过}
}

5.5. 业务调用层 RiskControlService

package com.example.riskcontrol;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.Map;@Service
public class RiskControlService {// 用Spring注解注入所有实现的模板,key为bean名字private final Map<String, RiskControlTemplate> riskControlMap;@Autowiredpublic RiskControlService(Map<String, RiskControlTemplate> riskControlMap) {this.riskControlMap = riskControlMap;}// 执行指定策略public void executeRiskControl(String strategyName, String userId) {RiskControlTemplate strategy = riskControlMap.get(strategyName);if (strategy == null) {throw new IllegalArgumentException("未找到对应风控策略:" + strategyName);}strategy.executeRiskControl(userId);}
}

5.6. Spring Boot 启动类

package com.example.riskcontrol;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringBootRiskControlApplication implements CommandLineRunner {@Autowiredprivate RiskControlService riskControlService;public static void main(String[] args) {SpringApplication.run(SpringBootRiskControlApplication.class, args);}@Overridepublic void run(String... args) throws Exception {System.out.println("模拟执行用户风控策略:");riskControlService.executeRiskControl("userRiskControl", "user12345");System.out.println("\n模拟执行交易风控策略:");riskControlService.executeRiskControl("transactionRiskControl", "user12345");}
}

5.7. 运行结果示例

模拟执行用户风控策略:
准备风控数据,用户ID:user12345
执行用户维度的风控规则校验,用户ID:user12345
风控拒绝,终止流程
记录风控结果,用户ID:user12345, 结果:拒绝模拟执行交易风控策略:
准备风控数据,用户ID:user12345
执行交易维度的风控规则校验,用户ID:user12345
风控通过,继续后续流程
记录风控结果,用户ID:user12345, 结果:通过

5.8. 模版模式总结

  • 抽象父类 RiskControlTemplate 封装公共流程(模板方法)。
  • 具体策略类只需实现风控规则校验步骤。
  • 通过 Spring 的 @Component 注解和自动装配 Map<String, RiskControlTemplate>,方便策略的灵活管理和调用。

6. 模版设计模式思考

6.1. 模版设计模式是不是用于父子类?

是的,模板设计模式(Template Method Pattern)确实是基于父子类继承关系实现的设计模式

6.1.1. 关键点总结:

  • 父类(抽象类):定义一个模板方法,规定算法的整体流程和执行顺序。模板方法通常是 final,防止子类改变流程。
  • 子类(具体类):继承父类,实现父类中定义的抽象步骤,完成具体业务逻辑。

换句话说,模板模式就是把不变的流程写在父类里,把可变的步骤留给子类实现。

6.1.2. 为什么是父子类?

  • 模板方法模式的核心就是“复用公共代码,且允许子类重写部分行为”,这是继承的典型应用场景。
  • 父类定义了算法框架,子类只实现细节,满足“开闭原则”(对扩展开放,对修改关闭)。

6.1.3. 举个简单类比:

  • 父类像“烘焙蛋糕的流程”
  • 子类像“不同口味蛋糕的具体做法”(巧克力、草莓等)

父类确定做蛋糕的步骤(比如准备材料、搅拌、烘焙、装饰),子类决定每步的具体实现。

模板设计模式在实战开发中常和以下设计模式配合使用,发挥协同优势:

6.2. 模版设计模式常和哪些模式用于实战开发中?

设计模式

结合方式及应用场景

策略模式

模板模式定义算法骨架,策略模式封装可替换的具体行为,实现灵活的步骤替换。比如模板方法中调用策略接口完成某步骤。

工厂方法模式

用工厂方法创建模板方法中需要的具体实现对象,解耦模板和具体子类的实例化。

钩子方法(Hook Method)

模板方法模式中提供可选的“钩子”方法,允许子类决定是否覆盖,灵活控制流程细节。

装饰器模式

在模板方法执行前后动态增强功能,如日志、权限校验等,避免修改模板代码。

责任链模式

将模板方法中的步骤拆分成责任链上的多个处理对象,形成更灵活的处理流程。

命令模式

模板方法中调用命令对象完成某些具体操作,命令模式封装请求,增强扩展性。

观察者模式

模板方法执行过程中发生重要事件时通知观察者,实现业务解耦。

简单示例场景

  • 金融风控:模板定义风控流程,策略模式封装不同风控规则。
  • Web请求处理:模板方法定义请求处理流程,工厂方法创建具体处理器。
  • 消息发送:模板定义消息发送步骤,装饰器动态添加日志或限流。

博文参考

  • 模板方法设计模式
  • 设计模式之模板方法模式 | DESIGN

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

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

相关文章

Python使用

Python学习&#xff0c;从安装&#xff0c;到简单应用 前言 Python作为胶水语言在web开发&#xff0c;数据分析&#xff0c;网络爬虫等方向有着广泛的应用 一、Python入门 相关基础语法直接使用相关测试代码 Python编译器版本使用3以后&#xff0c;安装参考其他教程&#xf…

吴恩达机器学习笔记(1)—引言

目录 一、欢迎 二、机器学习是什么 三、监督学习 四、无监督学习 一、欢迎 机器学习是当前信息技术领域中最令人兴奋的方向之一。在这门课程中&#xff0c;你不仅会学习机器学习的前沿知识&#xff0c;还将亲手实现相关算法&#xff0c;从而深入理解其内部机理。 事实上&…

java笔记08

多线程&JUC 1.什么是多线程 1.什么是多线程&#xff1f;有了多线程&#xff0c;我们就可以让程序同时做多件事情 2.多线程的作用&#xff1f;提高效率 3.多线程的应用场景&#xff1f;只要你想让多个事情同时运行就需要用到多线程比如&#xff1a;软件中的耗时操作、所有…

【仿muduo库实现并发服务器】使用正则表达式提取HTTP元素

使用正则表达式提取HTTP元素 1.正则表达式2.正则库的使用3.使用正则表达式提取HTTP请求行 1.正则表达式 正则表达式它其实是描述了一种字符串匹配的模式&#xff0c;它可以用来在一个字符串中检测一个特定格式的字串&#xff0c;以及可以将符合特定规则的字串进行替换或者提取…

显示即战略:铁电液晶如何成为 “数字中国” 的 “像素基石”?

一、显示技术&#xff1a;数字时代的核心战略支点 &#xff08;一&#xff09;从 “视觉窗口” 到 “战略基础设施” 在数字经济蓬勃发展的当下&#xff0c;显示技术早已超越了单纯的 “视觉呈现” 范畴&#xff0c;成为连接人与数字世界的关键接口。从智能手机、平板电脑到车…

适合小白的超详细配置YOLOv8教程(毕设必看)(训练自己数据集)(Pycharm保姆级安装教程)(lablme的使用)(GPU版)

目录 1.Pycharm的安装和虚拟环境调用&#xff08;已经安装好的可以跳过此步骤&#xff09; 1.1 下载pycharm软件 1.2 调用已创建虚拟环境&#xff08;调用上一篇教程中创建好的虚拟环境&#xff09; 2.标注自己数据集&#xff08;已有数据集的这部分可跳过&#xff09; 2.1…

EC800X QuecDuino开发板介绍

支持的模组列表 EG800KEC800MEC800GEC800E 功能列表 基本概述 EC800X QuecDuino EVB 搭载移远 EC800 系列模组。支持模组型号为&#xff1a; EC800M 系列、EC800K 系列、EG800K 系列、EC800E 系列等。 渲染图 开发板的主要组件、接口布局见下图 资料下载 EC800X-QuecDui…

Unity + HybirdCLR热更新 入门篇

官方文档 HybridCLR | HybridCLRhttps://hybridclr.doc.code-philosophy.com/docs/intro 什么是HybirdCLR? HybridCLR&#xff08;原名 huatuo&#xff09;是一个专为 Unity 项目设计的C#热更新解决方案&#xff0c;它通过扩展 IL2CPP 运行时&#xff0c;使其支持动态加载和…

类 Excel 数据填报

类 Excel 填报模式&#xff0c;满足用户 Excel 使用习惯 数据填报&#xff0c;可作为独立的功能模块&#xff0c;用于管理业务流程、汇总采集数据&#xff0c;以及开发各类数据报送系统&#xff0c;因此&#xff0c;对于报表工具而言&#xff0c;其典型场景之一就是利用报表模…

MySQL 8.0 OCP 英文题库解析(十)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题81~90 试题81:…

JavaScript 性能优化实战:从原理到框架的全栈优化指南

在 Web 应用复杂度指数级增长的今天&#xff0c;JavaScript 性能优化已成为衡量前端工程质量的核心指标。本文将结合现代浏览器引擎特性与一线大厂实践经验&#xff0c;构建从基础原理到框架定制的完整优化体系&#xff0c;助你打造高性能 Web 应用。 一、性能优化基础&#x…

基于Web的分布式图集管理系统架构设计与实践

引言&#xff1a;为什么需要分布式图集管理&#xff1f; 在现代Web图形应用中&#xff0c;纹理图集&#xff08;Texture Atlas&#xff09;技术是优化渲染性能的关键手段。传统的图集制作流程通常需要美术人员使用专业工具&#xff08;如TexturePacker&#xff09;离线制作&am…

鸿蒙OS在UniApp中集成Three.js:打造跨平台3D可视化应用#三方框架 #Uniapp

在UniApp中集成Three.js&#xff1a;打造跨平台3D可视化应用 引言 在最近的一个项目中&#xff0c;我们需要在UniApp应用中展示3D模型&#xff0c;并实现实时交互功能。经过技术选型和实践&#xff0c;我们选择了Three.js作为3D渲染引擎。本文将分享我们在UniApp中集成Three.…

Flask中关于app.url_map属性的用法

目录 一、app.url_map 是什么? 二、可以查看哪些信息? 三、示例:打印所有路由 四、结合 url_for() 使用 五、常见用途场景 六、结合 Flask CLI 使用 总结 app.url_map 是 Flask 中非常重要的一个属性,用于查看或操作整个应用的 URL 路由映射表(routing map)。它展…

SpringBoot项目搭建指南

SpringBoot项目搭建指南 文章目录 SpringBoot项目搭建指南一、SpringBoot项目搭建1.1 SpringBoot 版本选择1.2 SpringBoot 框架引入方式1.2.1 继承 Starter Parent POM1.2.2 不使用 Parent POM 来使用 Spring Boot 1.3 SpringBoot 打包插件 二、日志框架引入2.1 引入SpringBoot…

数据库系统概论(十六)数据库安全性(安全标准,控制,视图机制,审计与数据加密)

数据库系统概论&#xff08;十六&#xff09;数据库安全性 前言一、数据库安全性1. 什么是数据库安全性&#xff1f;2. 为何会存在安全问题&#xff1f; 二、安全标准的发展1. 早期的“开拓者”&#xff1a;TCSEC标准2. 走向国际统一&#xff1a;CC标准3. TCSEC和CC标准有什么不…

Jvm 元空间大小分配原则

JVM元空间&#xff08;Metaspace&#xff09;的大小分配原则与系统物理内存密切相关&#xff0c;但并不是直接等比例分配&#xff0c;而是通过一系列参数和JVM的动态管理机制来确定。下面从原理和实际行为两方面详细说明&#xff1a; 1. 元空间&#xff08;Metaspace&#xff0…

编程之巅:语言的较量

第一章&#xff1a;代码之城的召集令 在遥远的数字大陆上&#xff0c;有一座名为“代码之城”的神秘都市。这里居住着各种编程语言的化身&#xff0c;他们以拟人化的形态生活&#xff0c;每种语言都有独特的性格与技能。Python是个优雅的学者&#xff0c;C是个硬核战士&#x…

飞牛fnNAS装机之迷你小主机的利旧

前几天找Console线的时候,翻出一台迷你小主机,想起来以前是做“软路由”用的,现在用不上了。本想放回箱子,但突然想起最近正在做飞牛NAS的专题,不如将其改造成NAS得了。 这个东东有HDMI、VGA接口,2个USB(其中一个支持3.0),还有4个网口。 打开机盖,看看内部情况。发现…

uv:一个现代化的 Python 依赖管理工具

在 Python 的生态系统中&#xff0c;依赖管理和 Python 版本管理一直是开发者关注的核心问题。传统的工具如 pip、poetry 和 pyenv 虽然功能强大&#xff0c;但在性能和使用体验上仍有改进空间。uv 是由 Python 核心开发者开发的 现代化依赖管理工具&#xff0c;旨在提供更快、…