当前位置: 首页 > article >正文

一招搞定重复代码:模板方法模式实战

在日常撸代码的时候你肯定遇到过这种恶心的场景有几个业务流程它们整体的“套路”几乎是一模一样的只有中间那么一两个小步骤不一样。比如你要写一个解析文件的功能要支持解析 XML、JSON 和 CSV。这三者的流程都是下载文件 - 打开文件 - 【解析内容】 - 关闭文件 - 保存到数据库。除了【解析内容】这一步不一样其他的步骤简直是一个模子刻出来的。这时候很多新手的做法就是写三个类把相同的代码复制粘贴三遍。结果有一天产品经理说“下载文件之前先加个权限校验吧”得你只能苦逼地去那三个类里把权限校验的代码再补三遍。这要是漏改了一个直接就是一个线上 Bug。怎么解决这种“骨架相同细节不同”的痛点这时候就该请出设计模式里的老大哥——**模板方法模式Template Method Pattern**了。一、 什么是模板方法打个最简单的比方别去背网上那些晦涩难懂的定义。模板方法其实就是一套“固定流程的填空题”。想象一下你去星巴克看咖啡师做饮料。不管是做星巴克拿铁还是做冰摇红茶整体的流程其实都是固定的 4 步把水烧开。冲泡泡咖啡 or 泡茶。把饮料倒进杯子里。加小料加牛奶 or 加柠檬。在这 4 步里第 1 步和第 3 步是绝对固定的谁来做都一样。但第 2 步和第 4 步具体怎么做得看顾客点的是什么。在写代码时我们就可以把这个“固定的 4 步流程”写在一个父类里这就是模板然后把那些不确定的步骤冲泡、加小料留空让子类去具体实现。二、 用代码说话一看就懂废话不多说咱们直接上 Java 代码。第一步定义一个父类制作饮料的模板public abstract class BeverageTemplate { // 这就是我们的“模板方法”定义了核心的骨架流程 // 注意一定要加上 final 关键字防止子类瞎捣乱重写了这个大流程 public final void makeBeverage() { boilWater(); // 1. 烧开水固定 brew(); // 2. 冲泡不固定留给子类实现 pourInCup(); // 3. 倒入杯中固定 // 这是一个钩子方法Hook下面会详细讲 if (customerWantsCondiments()) { addCondiments(); // 4. 加小料不固定留给子类实现 } } // 固定步骤烧开水。直接在父类实现子类直接用 private void boilWater() { System.out.println(1. 烧开水...); } // 固定步骤倒进杯子。 private void pourInCup() { System.out.println(3. 把饮料倒进杯子里...); } // 抽象步骤冲泡。父类不管强制要求具体的子类去实现 protected abstract void brew(); // 抽象步骤加小料。强制要求子类实现 protected abstract void addCondiments(); // 钩子方法Hook给子类一个反悔的机会。默认是加小料的。 protected boolean customerWantsCondiments() { return true; } } ​第二步写具体的子类做咖啡和做茶先来个做咖啡的public class Coffee extends BeverageTemplate { Override protected void brew() { System.out.println(2. 用沸水冲泡咖啡粉); } Override protected void addCondiments() { System.out.println(4. 加糖和牛奶); } } ​再来个做茶的顺便用一下钩子方法假设这杯茶不加柠檬​public class Tea extends BeverageTemplate { Override protected void brew() { System.out.println(2. 用80度的水浸泡茶叶); } Override protected void addCondiments() { System.out.println(4. 加柠檬); } // 重写钩子方法返回 false表示这杯茶什么都不加 Override protected boolean customerWantsCondiments() { return false; } } ​第三步客户端调用public class Main { public static void main(String[] args) { System.out.println(--- 开始泡咖啡 ---); BeverageTemplate coffee new Coffee(); coffee.makeBeverage(); // 直接调模板方法 System.out.println(\n--- 开始泡纯茶 ---); BeverageTemplate tea new Tea(); tea.makeBeverage(); } } ​执行结果你会发现所有的流程都在你的掌控之中。如果是咖啡就走了 4 步如果是茶因为重写了钩子方法返回 false直接跳过了第 4 步。代码极其优雅。三、 拔高一点什么是“钩子Hook”在上面的代码里你看到了一个词叫“钩子Hook”。这是面试官非常喜欢问的一个细节。模板方法规定了死的骨架但有时候子类想要有一点**“微调的权力”**。比如整体流程是要加小料的但我今天偏偏想要一杯什么都不加的纯茶。这时候父类提供了一个返回 boolean 值的方法比如 customerWantsCondiments这就叫钩子。父类利用这个钩子来决定某些步骤要不要执行。子类如果不吭声不重写就按默认的来子类如果重写了就能通过钩子反向控制父类的流程。这其实完美体现了一个著名的好莱坞原则“Dont call us, well call you.”别打给我们我们会打给你。子类不需要主动去调用父类的方法而是父类把台子搭好到了需要子类表演的时候父类会自动调用子类实现的方法。四、 绝不仅仅是纸上谈兵框架里到处都是如果你觉得这就只是个泡咖啡的玩具代码那你就大错特错了。在我们天天用的神级框架里模板方法模式简直被用得烂大街了。Spring 框架里的各种 Template只要你在 Spring 里看到以 Template 结尾的类比如 JdbcTemplate、RedisTemplate、RestTemplate底层多多少少都用到了模板方法的思想。拿 JdbcTemplate 来说获取连接、创建 Statement、执行 SQL、处理异常、释放连接这套流程是死骨架模板而具体执行什么 SQL、怎么把结果映射成实体类则是留给你去实现的回调细节。Java Web 老古董HttpServlet还记得大学时写的 Servlet 吗你要写一个类继承 HttpServlet然后重写 doGet() 或者 doPost() 方法。其实 HttpServlet 内部有一个核心的 service() 方法它就是一个模板方法。它会根据 HTTP 请求的类型GET 还是 POST去路由调用对应的 doGet 或 doPost。你只需要在对应的方法里填空就行了根本不用管底层的 HTTP 协议是怎么解析的。并发编程的核心AQSAbstractQueuedSynchronizerJava 并发包JUC里的 ReentrantLock、CountDownLatch 等底层全靠 AQS 撑着。AQS 内部就把排队、阻塞、唤醒线程的骨架流程全部写好了。子类比如锁只需要重写 tryAcquire()尝试加锁和 tryRelease()尝试解锁这几个方法即可。这就是最顶级的模板方法应用。五、 总结一下什么时候该用模板方法只要你发现有多个类它们的整体操作步骤是一样的只有中间个别步骤的实现细节不同别犹豫直接抽出一个父类把骨架用 final 方法写死把差异留成 abstract 方法让子类去填空。好处代码复用率极高。以后要修改核心流程比如前面说的加个权限校验只需要改父类的一个地方所有子类自动生效再也不用满屏去找 CtrlC/V 的痕迹了。缺点由于 Java 是单继承的子类一旦继承了这个模板父类就不能再继承别的类了。而且如果业务变化太多可能会导致子类数量爆炸。总之模板方法模式是日常开发中最接地气、最容易落地的设计模式之一。掌握了它你的代码整洁度绝对能提升一个档次

相关文章:

一招搞定重复代码:模板方法模式实战

在日常撸代码的时候,你肯定遇到过这种恶心的场景: 有几个业务流程,它们整体的“套路”几乎是一模一样的,只有中间那么一两个小步骤不一样。比如你要写一个解析文件的功能,要支持解析 XML、JSON 和 CSV。 这三者的流程都…...

Chinese-CLIP模型微调实战:从数据准备到生产环境部署

在中文多模态任务中,CLIP模型展现出了巨大的潜力。它能够理解图像和文本之间的语义关联,为图像搜索、内容审核、智能推荐等场景提供了强大的基础能力。然而,原始的英文CLIP模型在中文语境下往往“水土不服”,直接应用效果不佳。因…...

激活函数调参指南:用PyTorch可视化ReLU/GELU/LeakyReLU的梯度差异与训练效果

激活函数调参实战:PyTorch可视化与梯度差异深度解析 在深度学习模型调优过程中,激活函数的选择往往被忽视,却直接影响着模型的收敛速度和最终性能。本文将带您深入ReLU、GELU和LeakyReLU三大主流激活函数的微观世界,通过PyTorch动…...

Xinference多模态实战:Qwen2-VL+Whisper+Stable-Diffusion-XL统一API调用示例

Xinference多模态实战:Qwen2-VLWhisperStable-Diffusion-XL统一API调用示例 Xinference版本:v1.17.1 1. 为什么需要统一的多模态API? 想象一下这样的场景:你需要让AI看懂图片、听懂语音、还能生成图像,传统做法是要部…...

技术面试流程与注意事项

技术面试是求职过程中至关重要的一环,它不仅考察候选人的专业能力,还考验其逻辑思维和问题解决能力。无论是应届毕业生还是资深工程师,掌握技术面试的流程与注意事项都能显著提升成功率。本文将详细介绍技术面试的常见流程,并从多…...

互联网产品需求分析助手:SmallThinker-3B-Preview评审PRD与生成用户故事

互联网产品需求分析助手:SmallThinker-3B-Preview评审PRD与生成用户故事 做产品,最怕什么?怕需求说不清,怕文档写不明,怕开发同学看完一脸懵,最后做出来的东西和你想的完全不是一回事。我自己带团队做产品…...

Python asyncio 异步爬虫实现

Python asyncio 异步爬虫实现:高效抓取数据的利器 在当今数据驱动的时代,网络爬虫成为获取信息的重要工具。传统的同步爬虫在面对大规模数据抓取时,往往因阻塞式I/O操作导致效率低下。Python的asyncio库提供了一种基于协程的异步编程模型&am…...

别再让Cesium地图卡顿了!手把手教你用EntityCluster实现高性能点聚合(附完整Vue3代码)

Cesium地图性能救星:EntityCluster点聚合实战指南 当你的智慧城市大屏上需要展示上万个物联网设备位置,或是物流监控系统要实时追踪数千辆运输车辆时,传统的点标记渲染方式很快就会让浏览器不堪重负。我曾接手过一个城市安防项目,…...

nlp_structbert_sentence-similarity_chinese-large 服务监控与调优:保障生产环境稳定性

nlp_structbert_sentence-similarity_chinese-large 服务监控与调优:保障生产环境稳定性 把模型服务部署上线,只是万里长征第一步。真正考验人的,是服务上线之后——怎么知道它跑得好不好?流量大了会不会崩?响应慢了用…...

UniApp打包避坑指南:从证书生成到上架全流程(Android/iOS双平台)

UniApp跨平台打包实战:Android/iOS全流程避坑手册 第一次将UniApp项目打包成原生应用时,我踩遍了所有能想到的坑——从证书过期导致的打包失败,到渠道包统计失灵,再到App Store审核被拒。这份手册正是基于三年跨平台开发经验&…...

从零配置glab:解决GitLab命令行工具认证失败的常见问题

从零配置glab:解决GitLab命令行工具认证失败的常见问题 对于开发者而言,高效管理GitLab仓库是日常工作中的重要环节。glab作为GitLab官方推荐的非官方命令行工具,提供了比原生Git更丰富的功能集,但初次配置时遇到的认证问题往往让…...

Chandra OCR作品分享:多页PDF自动分页+每页独立Markdown输出

Chandra OCR作品分享:多页PDF自动分页每页独立Markdown输出 1. 项目介绍 Chandra是Datalab.to在2025年10月开源的"布局感知"OCR模型,它能够将图片和PDF文件一键转换成保留完整排版信息的Markdown、HTML或JSON格式。这个模型的特别之处在于&a…...

嵌入式总体学习知识

...

百度指数数据分析实战:3步构建专业级搜索趋势监控系统

百度指数数据分析实战:3步构建专业级搜索趋势监控系统 【免费下载链接】spider-BaiduIndex data sdk for baidu Index 项目地址: https://gitcode.com/gh_mirrors/sp/spider-BaiduIndex 在数字营销和数据分析领域,实时掌握关键词搜索趋势已成为企…...

3大核心突破:InfiniteTalk多角色视频对话全栈指南

3大核心突破:InfiniteTalk多角色视频对话全栈指南 【免费下载链接】InfiniteTalk ​​Unlimited-length talking video generation​​ that supports image-to-video and video-to-video generation 项目地址: https://gitcode.com/gh_mirrors/in/InfiniteTalk …...

3个技巧掌握AI图像精准分割:Grounded-Segment-Anything实战指南

3个技巧掌握AI图像精准分割:Grounded-Segment-Anything实战指南 【免费下载链接】Grounded-Segment-Anything Grounded-SAM: Marrying Grounding-DINO with Segment Anything & Stable Diffusion & Recognize Anything - Automatically Detect , Segment an…...

AI写论文优选!4款AI论文生成工具揭秘,高效搞定期刊论文不发愁!

AI论文写作工具实测推荐 还在为撰写期刊论文而烦恼吗?面对海量的学术文献、繁杂的格式要求和反复修改的过程,很多学术工作者都感到力不从心!但是不要担心,以下推荐的4款AI论文写作工具,经过实测,能够帮助你…...

腰痛伴随臀部疼,不是单纯腰突,多是梨状肌综合征混淆病情

腰痛连着臀部疼,甚至放射到大腿后侧,很多人直接当成腰椎间盘突出治疗,按摩、牵引做了一大堆,症状却没有缓解,反而越来越重,其实这种疼痛,大概率是梨状肌综合征在作祟,和腰突症状相似…...

GPT AI Assistant命令系统详解:从痛点解决到高效应用

GPT AI Assistant命令系统详解:从痛点解决到高效应用 【免费下载链接】gpt-ai-assistant OpenAI LINE Vercel GPT AI Assistant 项目地址: https://gitcode.com/GitHub_Trending/gp/gpt-ai-assistant 一、命令操作的三大痛点与解决方案 在使用GPT AI Ass…...

CppSharp全面指南:如何实现C++到.NET的自动化绑定开发

CppSharp全面指南:如何实现C到.NET的自动化绑定开发 【免费下载链接】CppSharp Tools and libraries to glue C/C APIs to high-level languages 项目地址: https://gitcode.com/gh_mirrors/cp/CppSharp CppSharp是一款专业的跨语言绑定工具,核心…...

汽车仿真与参数代改:Matlab 的魔法之旅

matlab代改车辆参数,擅长Advisor仿真 混合动力等效最小能耗ECMS参数代改DP动态跟随,规则算法-功率跟随控制燃料电池汽车能量管理策略模型代改 燃料电池汽车,纯电动复合电源及能量管理,模糊控制,小波模糊控制&#xff1…...

从OJ题到实战:手把手教你用C++实现二叉排序树的查找(附完整代码与避坑点)

从OJ题到实战:手把手教你用C实现二叉排序树的查找(附完整代码与避坑点) 二叉排序树(Binary Search Tree, BST)是数据结构课程中的经典内容,也是算法面试和在线评测系统(OJ)中的常客。…...

颗粒流环形剪切实验:用代码扒开土体的秘密

PFC3D5.0颗粒流『颗粒材料/土体材料环形剪切实验』完整代码 该代码包括: (1)完整代码及适量注释,可以参考学习,也可直接使用,无需调试; (2)环形剪切实验的建模全过程&…...

Wan2.2-I2V-A14B零基础入门:5分钟学会用图片生成高清视频

Wan2.2-I2V-A14B零基础入门:5分钟学会用图片生成高清视频 1. 为什么选择Wan2.2-I2V-A14B 想用一张静态图片变成生动的视频吗?Wan2.2-I2V-A14B让这个想法变得简单。这个模型专门为图片转视频设计,即使你没有任何AI经验,也能在几分…...

Leela Zero容器化部署指南:跨平台AI围棋引擎的高效实践方案

Leela Zero容器化部署指南:跨平台AI围棋引擎的高效实践方案 【免费下载链接】leela-zero Go engine with no human-provided knowledge, modeled after the AlphaGo Zero paper. 项目地址: https://gitcode.com/gh_mirrors/le/leela-zero 核心价值&#xff1…...

Vue3 知识点总结 · 2026-03-24

Vue3 知识点总结 2026-03-24 👨‍💻 嘿!大家好 👋前后端开发工程师 日更 CSDN & 掘金我是一名对代码狂热的 IT 工作者,目前在一家公司任职前后端开发工程师。以后每天都会更新 CSDN 和稀土掘金的文章——工作中写…...

OpenClaw压力测试:nanobot镜像并发任务处理极限

OpenClaw压力测试:nanobot镜像并发任务处理极限 1. 为什么需要测试OpenClaw的并发能力 当我第一次听说OpenClaw可以7*24小时不间断工作时,最让我好奇的是它的并发处理能力。作为一个经常需要批量处理文件的开发者,我需要知道这个工具在同时…...

3分钟实现手机号查QQ号:无需登录的Python实用工具

3分钟实现手机号查QQ号:无需登录的Python实用工具 【免费下载链接】phone2qq 项目地址: https://gitcode.com/gh_mirrors/ph/phone2qq phone2qq是一款轻量级Python工具,能够帮助用户通过手机号快速查询关联的QQ账号,全程无需登录QQ客…...

java+vue+SpringBoot计算机学院校友网(程序+数据库+报告+部署教程+答辩指导)

源代码数据库LW文档(1万字以上)开题报告答辩稿ppt部署教程代码讲解代码时间修改工具 技术实现 开发语言:后端:Java 前端:vue框架:springboot数据库:mysql 开发工具 JDK版本:JDK1.8 数…...

Servlet 过滤器(Filter)

一、过滤器是什么?统一处理所有请求 / 响应,不用每个 Servlet 都写重复代码!Servlet 过滤器 服务器端的 “门卫 / 拦截器”它在 请求到达 Servlet 之前 先拦截也可以在 响应返回客户端之前 再处理可以对请求、响应、会话做统一处理一个项目可…...