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

【设计模式】之模板方法模式

系列文章目录

  • 【设计模式】之策略模式

  • 【设计模式】之责任链模式

文章目录

系列文章目录

前言

一、什么是模板方法模式

定义

 角色 

二、为什么要使用模板方法模式

优点

缺点

三、案例

普通案例

模拟Servlet过程案例

总结


前言

今天给大家介绍23种设计模式中的模板方法模式,这个设计模式在Spring框架中还是挺常见的,手写Spring源码的小伙伴必须要掌握的设计模式之一,文章结构还是经典的三连问,是什么?为什么?怎么用?🌈


一、什么是模板方法模式

定义

模板方法模式法(Template Method)定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。

 角色 

  • 抽象类(Abstract Class):负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
    • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
    • 基本方法:是实现算法各个步骤的方法。基本方法又可以分为三种:
      • 钩子方法(Hook Method) :在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种。一般钩子方法是用于判断的逻辑方法,这类方法名一般为isXxx,返回值类型为boolean类型。
      • 具体方法(Concrete Method) :一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。
      • 抽象方法(Abstract Method) :一个抽象方法由抽象类声明、由其具体子类实现。
  • 具体子类(Concrete Class):实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。

二、为什么要使用模板方法模式

优点

  • 代码复用:模板方法将公共的代码放在父类中,子类可以通过继承来复用这部分代码,从而避免在子类中重复编写相同的代码。
  • 算法统一:模板方法确保了算法的整体结构在子类中是一致的,只是某些步骤的实现有所不同。这有助于保持算法的统一性和完整性。
  • 灵活性:模板方法允许子类通过实现抽象方法来定制算法的特定步骤,从而提供了很大的灵活性。
  • 扩展性:如果需要增加新的算法步骤,只需要在父类的模板方法中添加新的抽象方法,并让子类实现这些方法即可,无需修改现有的子类代码。

缺点

  • 增加继承层次:使用模板方法设计模式会增加类的继承层次,这可能会导致系统变得复杂,并增加维护成本。
  • 子类数量过多:如果算法中有很多可变步骤,那么可能需要定义很多抽象方法,从而导致子类数量过多。这会增加系统的复杂性,并可能导致“爆炸式”的子类增长。
  • 违反单一职责原则:有时模板方法可能会包含过多的逻辑,导致父类承担了过多的职责。这违反了单一职责原则,使得父类变得难以维护和扩展。

因此,在使用模板方法设计模式时,需要权衡其优缺点,根据具体场景和需求来决定是否使用以及如何使用该模式。

三、案例

普通案例

炒菜步骤:打开油烟机->生火->炒菜->关火->关闭油烟机,我们就以这个步骤为例,不管炒什么菜都会经过 打开油烟机、生火、关火、关闭油烟机这四个步骤,因此,我们可以将这几个过程定义为一个模板方法,至于炒什么样的菜,让子类去决定。

public abstract class Cook {public void open(){System.out.println("打开抽油烟机");}public void openFire(){System.out.println("生火");}//设置为抽象方法,由每个对象重写这个方法(决定做什么菜)public abstract void doCook();public void closeFire(){System.out.println("关火");}public void close(){System.out.println("关闭抽油烟机");}//做饭模板方法public final void cook(){this.open();this.openFire();this.doCook();this.closeFire();this.close();}
}

子类去继承Cook类实现里面的抽象方法去决定做什么菜。

public class CookPotato extends Cook{@Overridepublic void doCook() {System.out.println("酸辣土豆丝");}
}public class CookTomato extends Cook{@Overridepublic void doCook() {System.out.println("西红柿炒鸡蛋");}
}
 @Testvoid test1(){Cook cookPotato = new CookPotato();cookPotato.cook();System.out.println("==========");Cook cookTomato = new CookTomato();cookTomato.cook();}/*
打开抽油烟机
生火
酸辣土豆丝
关火
关闭抽油烟机
==========
打开抽油烟机
生火
西红柿炒鸡蛋
关火
关闭抽油烟机
*/

模拟Servlet过程案例

我们平常使用的Servlet就是一个典型的模板方法的设计模式。

我们平常使用一般是继承HttpServlet这个类,然后去重写类面的一些方法,如:doGet、doPost、doPut等等

public class testServlet extends MyHttpServlet{@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse response) {System.out.println("执行doGet方法");}@Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response) {System.out.println("执行doPost方法");}
}

HttpServlet会继承GenericServlet这个类,HttpServlet会将ServletRequestServletResponse强转为HttpServletRequestHttpServletResponse,并对方法类型进行判断派发。

public abstract class MyHttpServlet extends MyGenericServlet{@Overridepublic void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {HttpServletRequest request = (HttpServletRequest) servletRequest;HttpServletResponse response = (HttpServletResponse) servletResponse;switch (request.getMethod()){case "GET":this.doGet(request,response);break;case "POST":this.doPost(request,response);break;}}public abstract void doGet(HttpServletRequest request, HttpServletResponse response);public abstract void doPost(HttpServletRequest request, HttpServletResponse response);
}

GenericServlet实现Servlet这个接口,去实现servlet生命周期方法。

public abstract class MyGenericServlet implements Servlet {@Overridepublic void init(ServletConfig servletConfig) throws ServletException {System.out.println("正在初始化");}@Overridepublic ServletConfig getServletConfig() {return null;}@Overridepublic abstract void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException ;@Overridepublic String getServletInfo() {return null;}@Overridepublic void destroy() {System.out.println("正在销毁");}
}

整个大致过程可以总结为:GenericServlet过滤生命周期方法,将service()方法交给HttpServlet去实现,HttpServlet负责将实现具体的方法,最后就得到了我们常见的doGet等方法,我说的这个过程比较简单,其实Servlet整个过程还是挺复杂的,我就抛砖引玉,给大家熟悉下模板方法这个设计模式。


总结

不管哪一种方法模式,都各有利弊,我们平常在开发的过程中,一定要选择最优的解决方式,不可盲目使用。今天的分享就到这里,我们下期再见。✋

相关文章:

【设计模式】之模板方法模式

系列文章目录 【设计模式】之策略模式 【设计模式】之责任链模式 文章目录 系列文章目录 前言 一、什么是模板方法模式 定义 角色 二、为什么要使用模板方法模式 优点 缺点 三、案例 普通案例 模拟Servlet过程案例 总结 前言 今天给大家介绍23种设计模式中的模板方法模式&a…...

【系统架构师】-选择题(十一)

1、紧耦合多机系统一般通过(共享内存)实现多机间的通信。对称多处理器结构(SMP)属于( 紧耦合)系统。 松耦合多机系统又称间接耦合系统,—般是通过通道或通信线路实现计算机间的互连。 2、采用微内核的OS结构…...

前端开发攻略---介绍HTML中的<dialog>标签,浏览器的原生弹框。

1、演示 2、介绍 <dialog> 标签用于定义对话框&#xff0c;即一个独立的窗口&#xff0c;通常用来显示对话框、提示框、确认框等弹出式内容。在对话框中&#xff0c;可以包含文本、表单元素、按钮等内容&#xff0c;用户可以和这些内容进行交互。 3、兼容性 4、示例代码 …...

让外贸业绩翻倍的销售话术分享

业绩翻三倍的话术&#xff0c;今后无论你遇到挑剔、犹豫、理智的顾客&#xff0c;都能轻松搞定。点赞存起来慢慢看&#xff0c;以免找不到。 与客户有效沟通技巧5的20句金句 业绩翻 3 倍&#xff0c;今后无论你遇到挑剔、犹豫、理智的顾客&#xff0c;都能轻松搞定。点赞存起来…...

观测与预测差值自动变化系统噪声Q的自适应UKF(AUKF_Q)MATLAB编写

简述 基于三维模型的UKF&#xff0c;设计一段时间的输入状态误差较大&#xff0c;此时通过对比预测的状态值与观测值的残差&#xff0c;在相应的情况下自适应扩大系统方差Q&#xff0c;构成自适应无迹卡尔曼滤波&#xff08;AUKF&#xff09;&#xff0c;与传统的UKF相比&…...

虚拟数据中心

创建数据中心和连接宿主机 DRS:收集群集内所有主机和虚拟机的资源使用情况信息&#xff0c;并根据特定的运行状况给出建议或迁移虚拟机HA:如果一台主机出现故障&#xff0c;则该主机上运行的所有虚拟机都将立即在同一群集的其他主机上重新启动EVC:增强型vMotionVirtual SAN:集中…...

解决Blender导出FBX文件到Unity坐标轴错误的问题

发现Blender的模型导入到Unity里面有问题,简单研究了下发现是坐标系不同,Unity使用的是左手坐标系,Blender使用的是右手坐标系 。 下面直接将如何解决 首先忽略Blender的右手坐标系以及Z轴朝上的事&#xff0c;依照unity坐标系情况修改模型物体的旋转&#xff0c;以Blender猴…...

基于微信小程序的校园二手闲置物品交易平台的设计与实现

基于微信小程序的校园二手闲置物品交易平台的设计与实现 “Design and Implementation of a Campus Second-Hand Marketplace Platform based on WeChat Mini Program” 完整下载链接:基于微信小程序的校园二手闲置物品交易平台的设计与实现 文章目录 基于微信小程序的校园二…...

java中多线程的3种实现方法

1.继承Thread类 优点&#xff1a;代码简单&#xff0c;可以直接使用Thread类里面的方法。 缺点&#xff1a;扩张性较差&#xff0c;应为在java中&#xff0c;一个类只能继承一个父类。 2.实现Runnable接口 3.实现Callable接口 2和3的优缺点是一样的 优点&#xff1a;扩展性强&…...

【Docker】docker compose服务编排

docker compose 简介 Dockerfile模板文件可以定义一个单独的应用容器&#xff0c;如果需要定义多个容器就需要服务编排。 docker swarm&#xff08;管理跨节点&#xff09; Dockerfile可以让用户管理一个单独的应用容器&#xff1b;而Compose则允许用户在一个模板&#xff08…...

elementui的el-select+el-tree+el-input实现可搜索的下拉树组件

部分实现代码如下 <template> <div><el-selectv-model"item.TableName"placeholder"请选择":disabled"!item.disabled"visible-change"handleVisible"ref"TableName"><el-input placeholder"请输…...

微信公众号排名 SEO的5个策略

随着微信公众号在社交媒体领域的持续发展和普及&#xff0c;如何提升公众号的搜索排名&#xff0c;成为许多运营者关注的焦点。公众号排名SEO&#xff0c;即针对微信公众号进行搜索引擎优化&#xff0c;旨在提高公众号在搜索结果中的曝光率和点击率。下面&#xff0c;我们将深入…...

python烟花代码

在Python中&#xff0c;可以使用多种方式来模拟烟花效果&#xff0c;其中一种常见的方法是使用turtle图形库来绘制。以下是一个简单的示例&#xff0c;展示了如何使用turtle来创建一个烟花效果的动画&#xff1a; import turtle import random# 设置屏幕和背景 screen turtle…...

Python高级编程

描述 集合&#xff0c;列表生成式&#xff0c;生成器&#xff0c;迭代器&#xff0c;切片 Python 中的集合类型是一种无序、不重复的数据容器&#xff0c;用于存储可哈希&#xff08;hashable&#xff09;的元素。Python 提供了两种内置的集合类型&#xff1a;set 和 frozens…...

leetCode75. 颜色分类

leetCode75. 颜色分类 题目思路 代码 class Solution { public:void sortColors(vector<int>& nums) {for(int i 0, j 0, k nums.size() - 1; i < k;){if(nums[i] 0) swap(nums[i],nums[j]);else if(nums[i] 2) swap(nums[i],nums[k--]);else if(nums[i] …...

选择器、pxcook软件、盒子模型

结构伪类选择器 定义&#xff1a;根据结构的元素关系来查找元素。 <title>Document</title><style>li:first-child{color:aqua ;}li:last-child{color: aqua;}li:nth-child(3){color: aqua;}</style> </head> <body><ul><li>…...

商城系统秒杀功能设计思想

业务特点 1、瞬时并发量大&#xff0c;秒杀时会有大量用户在同一时间进行抢购&#xff0c;瞬时并发访问量突增几倍、甚至几十倍以上 2、库存量少&#xff0c;一般秒杀活动商品量很少&#xff0c;这就导致了只有极少量用户能成功购买到。 3、业务和流程较为常见&#xff0c;一般…...

#初始化列表

1.再谈构造函数 1.1构造函数的组成 构造函数包括函数体赋值与初始化列表初始化。 1.2函数体赋值 class Date { public:Date(int year, int month, int day){_year year;_month month;_day day;} private:int _year;int _month;int _day; };虽然上述构造函数调用之后&…...

Vue-组件中的data

一个组件的data选项必须是一个函数。保证每个组件实例&#xff0c;维护独立的一份数据对象。如下图&#xff1a; 组件一旦封装好了&#xff0c;可以使用多次&#xff0c;比如数字框组件使用了三次&#xff1a; 每次创建新的组件实例&#xff0c;都会重新执行一次data函数&#…...

抖音小店达人佣金应该怎么结算呢?给达人设置多少佣金合适?

大家好&#xff0c;我是电商小V 咱们在运营抖音小店的时候一定会遇到被达人催促结算佣金的情况&#xff0c;咱们给达人合作的时候都会遇到过新手达人&#xff0c;就是给咱们直播带货之后催促咱们赶紧结算商品的佣金&#xff0c; 但是咱们都需要知道一点&#xff0c;那就是小店的…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

HashMap中的put方法执行流程(流程图)

1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中&#xff0c;其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下&#xff1a; 初始判断与哈希计算&#xff1a; 首先&#xff0c;putVal 方法会检查当前的 table&#xff08;也就…...

佰力博科技与您探讨热释电测量的几种方法

热释电的测量主要涉及热释电系数的测定&#xff0c;这是表征热释电材料性能的重要参数。热释电系数的测量方法主要包括静态法、动态法和积分电荷法。其中&#xff0c;积分电荷法最为常用&#xff0c;其原理是通过测量在电容器上积累的热释电电荷&#xff0c;从而确定热释电系数…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...