策略模式和模板方法模式的区别【面试题】

策略模式和模板方法模式的区别【面试题】

摘要:
策略模式和模板方法模式均属于行为设计模式,但核心差异显著。策略模式通过组合实现,支持运行时动态切换完整算法(如支付方式切换),变化维度大;模板方法模式通过继承实现,固定算法骨架但允许子类定制特定步骤(如文档生成流程不变,数据源可变),变化维度小。前者由调用方主动选择策略(控制权在客户端),后者遵循“好莱坞原则”由父类控制流程调用子类方法(控制权在父类)。选择依据:需灵活替换整套逻辑用策略模式;需复用流程但微调步骤用模板方法模式。

简单记忆:

第一,机制不同。模板方法靠继承,策略靠组合。这意味着模板方法在编译时就确定了行为扩展(通过子类化)相对变化小,而策略可以在运行时切换,变化的大。

第二,变化维度不同。模板方法变化的是算法中的某些步骤,整体流程不变;策略变化的是整个算法实现。就像做菜,模板方法是固定了“洗菜-切菜-烹饪”流程但允许换刀工,策略则是直接换菜系。

第三,控制方向相反。模板方法由父类控制流程调用子类方法(好莱坞原则),策略是调用方主动选择策略对象。

策略模式(Strategy Pattern)和模板方法模式(Template Method Pattern)都是行为设计模式,都用于封装变化的部分,但它们解决问题的角度、实现机制和适用场景有本质区别。以下是两者核心区别的清晰对比:

1)相同点

策略模式(Strategy Pattern)和模板方法模式(Template Method Pattern)都是行为设计模式,都用于封装变化的部分,但它们解决问题的角度、实现机制和适用场景有本质区别。以下是两者核心区别的清晰对比:

2)不同点

2.1)核心目标不同

  • 策略模式:
    替换整个算法
    目标是定义一系列可互换的算法,让客户端能根据需要动态切换不同的算法实现,且算法的变化不影响使用它的上下文。
    👉 核心:算法的完整替换。
  • 模板方法模式:
    定义算法的骨架,允许子类重写特定步骤
    目标是固定一个操作的整体流程结构,仅允许子类修改流程中的某些步骤(变化点),而不改变算法的主干。
    👉 核心:算法骨架不变,步骤细节可变。

2.2)实现机制不同

特性策略模式模板方法模式
关系类型组合(Has-a)继承(Is-a)
关键参与者Context 持有 Strategy 接口的引用抽象类定义 模板方法 + 抽象步骤方法
扩展方式新增 Strategy 实现类创建子类并实现抽象方法/覆盖钩子方法
运行时行为可动态切换策略对象子类行为在编译时确定(通过继承)
控制流方向Context 委托给策略对象执行父类调用子类方法(“好莱坞原则”)

2.3)变化点不同

  • 策略模式:
    变化的是整个算法逻辑
    例如:支付时在 支付宝信用卡PayPal完全不同的支付逻辑之间切换。
  • 模板方法模式:
    变化的是算法中的某些步骤整体流程固定不变
    例如:文档生成流程 打开模板->填充数据->保存文件 中,填充数据 的方式可变(填数据库数据/API数据),但步骤顺序不变。

2.4)代码结构对比

策略模式伪代码

// 策略接口
interface CompressionStrategy {void compress(File file);
}// 具体策略
class ZipCompression implements CompressionStrategy {void compress(File file) { /* ZIP压缩逻辑 */ }
}class RarCompression implements CompressionStrategy {void compress(File file) { /* RAR压缩逻辑 */ }
}// 上下文(组合策略)
class Compressor {private CompressionStrategy strategy;void setStrategy(CompressionStrategy s) { this.strategy = s; }void compressFile(File file) {strategy.compress(file); // 委托给当前策略}
}// 使用:动态切换策略
Compressor compressor = new Compressor();
compressor.setStrategy(new ZipCompression()); // 运行时切换为ZIP
compressor.compressFile(file);

模板方法模式伪代码

// 抽象类(定义模板骨架)
abstract class DataExporter {// 模板方法 (final 防止子类覆盖流程)public final void export() {openConnection();fetchData();      // 抽象方法 -> 子类实现transformData();  // 钩子方法 -> 子类可选覆盖save();           // 抽象方法 -> 子类实现closeConnection();}protected abstract void fetchData();protected abstract void save();protected void transformData() {} // 默认空实现(钩子方法)private void openConnection() { /* 通用逻辑 */ }private void closeConnection() { /* 通用逻辑 */ }
}// 具体子类
class CSVExporter extends DataExporter {protected void fetchData() { /* 从DB取数据 */ }protected void save() { /* 存为CSV */ }
}class JSONExporter extends DataExporter {protected void fetchData() { /* 从API取数据 */ }protected void save() { /* 存为JSON */ }protected void transformData() { /* 自定义数据转换 */ } // 覆盖钩子
}// 使用:子类继承固定流程
DataExporter exporter = new CSVExporter();
exporter.export(); // 执行固定流程+子类实现的步骤

2.5) 适用场景对比

场景策略模式模板方法模式
算法需要动态切换✅ 支付方式、排序算法、导航策略等❌ 子类行为在编译时绑定
多个类有相同流程但不同步骤✅ 框架生命周期、文档生成、ETL流程
避免重复的流程代码✅ 将通用流程抽取到父类
隐藏算法实现细节✅ 客户端只依赖策略接口❌ 子类需知晓抽象步骤
扩展新算法/行为✅ 新增策略类即可✅ 新增子类实现抽象步骤
控制子类扩展点✅ 用 final 模板方法保护核心流程
关键总结:一句话区分
  • 策略模式“换整套方案”
    → 通过组合动态切换完整算法(如支付时换整套支付逻辑)。
  • 模板方法模式“固定流程,定制步骤”
    → 通过继承固定算法骨架,子类定制某些步骤(如报告生成流程固定,但数据来源和格式可定制)。

💡 简单记忆

  • 需要运行时灵活替换整个算法?→ 策略模式(组合)。
  • 需要复用固定流程但允许步骤自定义?→ 模板方法模式(继承)。

喜欢我的文章记得点个在看,或者点赞,持续更新中ing…

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

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

相关文章

从零打造前沿Web聊天室:消息系统

消息存储系统 聊天室设计,消息存储系统非常关键,因为一开始设计时使用MongoDB,所以后续使用schemma方式存储。 后端架构:express MongoDB 消息插入策略 在 MongoDB 中设计聊天消息存储时,插入策略的选择会影响性能…

[7-01-03].第03节:环境搭建 - 集群架构

RabbitMQ学习大纲 一、使用集群的原因 1.基于以下原因,需要搭建一个 RabbitMQ 集群来解决实际问题 单机版的,无法满足目前真实应用的要求。如果 RabbitMQ 服务器遇到内存崩溃、机器掉电或者主板故障等情况,会导致rabbitMQ无法提供服务单台 R…

【vivado】时序分析之Latch pins with no clock

问题: vivado打开时序报告,如下图 表示存在锁存器Latch 解决方法: 查看代码中是否存在状态机的状态没有写全,或者default中直接写了null。

如何将 MX Linux 的垂直任务栏面板移到底部

MX Linux 因其速度和较低的资源消耗,比同类其他 Linux 系统更快地获得了人气。它默认带有 Xfce 桌面环境,但任务栏在左侧且是垂直的,这对一部分人来说真的非常不舒服且令人烦恼。如果你也有同感,并且也想将 MX Linux 的任务栏自定…

python debug 监控双下划线的变量显示没有此变量

名称改写(Name Mangling) 在Python中,如果你在类中定义一个属性或方法时以双下划线开头(例如__attribute),Python会自动对其进行名称改写。名称改写实际上是在属性或方法名前加上类名,以避免子…

list使用及模拟

01. list介绍 list是支持常数时间内任意位置插入删除的序列容器,具备双向迭代能力。其底层为双向链表结构,各元素存于独立节点,通过指针指向前后元素。与forward_list的主要区别:后者是单链表,仅支持单向迭代,结构更简单高效。相比array、vector、deque等序列容器,list在…

NLP基础与词嵌入:让AI理解文字(superior哥深度学习系列第13期)

13_NLP基础与词嵌入:让AI理解文字 superior哥深度学习系列第十三篇 从像素到文字,从视觉到语言——让AI跨越认知的桥梁 🎯 前言:当AI学会"读懂"文字 各位小伙伴们,欢迎来到superior哥深度学习系列的第十三篇…

【时时三省】(C语言基础)关于变量的声明和定义

山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 可能有些人弄不清楚定义与声明有什么区别,它们是否是一回事。有人认为声明就是定义,有人认为只有赋了值的才是定义。在C语言的学习中,关于定义与声明这两个…

Java 时间处理指南:从“踩坑”到“填坑”实战

🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 场景问题:订单处理系统的时间计算 假设你正在开发一个电商订单系统,需要解决以下问题: 用户下单后,需在…

基于Java的Excel列数据提取工具实现

摘要:本文介绍了一个使用Java语言开发的Excel列数据提取工具,该工具借助Apache POI库实现对Excel文件的读取与特定列数据提取功能。通过用户输入文件路径与列名,程序可从指定Excel文件中提取相应列的数据并展示,同时详细阐述了关键…

关于人工智能未来的趋势

学而不思则罔 翻译:使用深度学习、强化学习却不用专家系统,就会产生幻觉。 思而不学则殆 翻译:只有专家系统逻辑推理,但是不用大模型更新知识,就无法发展下去了。 因此,未来智能的范式应该是: …

Java八股文——MySQL「性能调优篇」

MySQL的EXPLAIN有什么作用? 面试官您好,EXPLAIN命令是我在进行SQL性能优化时,使用最频繁、也最重要的一个工具。 它的核心作用可以一句话概括:模拟MySQL的查询优化器来执行一条SQL语句,并向我们展示出它最终决定采用…

win打印机共享处理

win打印机共享处理 软件链接 无法启动Print Spooler服务错误193:0xc1的解决方案主要涉及修复服务依赖关系、清理打印缓存及修复系统文件‌。该错误通常由系统文件损坏、注册表配置异常或依赖服务未启动导致,可通过以下步骤系统化解决。‌‌ 解决方法:替换…

C++ map代码练习 1、2、priority_queue基础概念、对象创建、数据插入、获取堆顶、出队操作、大小操作,自定义结构、代码练习 1 2

map代码练习1&#xff0c;对应力扣 两个数据的交集&#xff0c;代码见下 class Solution { public:vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {map<int, int> cnt;vector<int> ans;for(int i0; i<nums1.size(…

三天冲刺《编译原理》——笔记(一)

点关注不迷路哟。你的点赞、收藏&#xff0c;一键三连&#xff0c;是我持续更新的动力哟&#xff01;&#xff01;&#xff01; 持续关注我~~~主页&#xff0c;查看更多内容哟&#xff08;希望你能在这里有所收获&#x1f92d;&#xff09;。点关注&#xff0c;不迷路&#xf…

代理模式Proxy Pattern

模式定义 给某一个对象提供一个代理&#xff0c;并由代理对象控制对原对象的引用 对象结构型模式 模式结构 Subject&#xff1a;抽象主题角色Proxy&#xff1a;代理主题角色RealSubject&#xff1a;真实主题角色 代理类实现代码 public class Proxy implements Subject {p…

基于YOLOv11与单目测距的实战教程:从目标检测到距离估算

引言 在计算机视觉领域&#xff0c;目标检测与距离估算的结合是自动驾驶、机器人导航等场景的关键技术。本文将以YOLOv8模型为核心&#xff0c;结合单目相机的几何模型&#xff0c;实现对视频中目标的实时检测与距离估算。代码参考自单目测距原理博客&#xff0c;并通过实践验…

代码生成器使用原理以及使用方法

代码生成器使用原理以及使用方法 版本号&#xff1a;1.0 二Ο二五年二月 目录 文档介绍 1.1编写目的 1.2文档范围 1.3读者对象 系统设计 2.1设计目标 2.2设计思路 2.3代码实现原理 使用方法 3.1如何使用 3.2如何修改&#xff1f; 对原程序的bug修改及简…

STM32标准库-I2C通信

文章目录 一、I2C通信1.1 I2C1.2硬件电路1.3I2C时序基本单元1.4I2C时序 二、MPU60502.1简介2.2MPU6050参数2.3硬件电路2.4MPU6050框图 三、I2C外设(硬件)3.1简介3.2I2C框图3.3I2C基本结构3.4主机发送3.5主机接收3.6软件/硬件波形对比1. 时序精度2. 信号稳定性3. 速率与效率4. 波…

使用 Azure LLM Functions 与 Elasticsearch 构建更智能的查询体验

作者&#xff1a;来自 Elastic Jonathan Simon 及 James Williams 试用这个示例房地产搜索应用&#xff0c;它结合了 Azure Gen AI LLM Functions 与 Elasticsearch&#xff0c;提供灵活的混合搜索结果。在 GitHub Codespaces 中查看逐步配置和运行该示例应用的方法。 更多阅读…