23种设计模式 - 模板方法模式

1. 认识模板方法模式

1.1 模式定义

定义一个操作算法中的框架,而将这些步骤延迟加载到子类中。

它的本质就是固定算法框架。

1.2 解决何种问题

让父类控制子类方法的调用顺序

模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

1.3 模式好处

开发人员在开发时,只需要考虑方法的实现。不需要考虑方法在何种情况下被调用。实现代码复用。

1.4 模式适合场景
  • 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
  • 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
  • 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

2. 模式结构与实例讲解

2.1模式结构

模板方法模式结构图


如模板方法模式结构图所知,有两个类:

  • AblstractClass(抽象类):在抽象类中定义了一系列的操作PrimitiveOperation,每个操作可以使具体的,也可以是抽象的,每个操作对应一个算法的步骤,在子类中可以重新定义或实现这些步骤。TmplateMethod()这个方法用于定义一个算法结构,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。
  • ConcreteClass(具体子类):用于实现在父类中声明的抽象基本操作,也可以覆盖在父类中已经实现的具体基本操作。
2.2 实例讲解

创建一个抽象模板结构(AblstractClass)好父亲

public abstract class AblstractClass {//模板方法用来控制子类的顺序 要想有人生必须按老爸的人生顺序来  //声明final不让子类覆盖这个方法,防止改变人生顺序public final void 人生(){学习();工作();爱情();}//家里穷更得用工学习public void 学习(){System.out.println("每天晚上趴在邻居窗上学习");}//工作必须稳定public void 工作(){       System.out.println("从一而终");}//恋爱自由  让儿子自由恋去public abstract void 爱情();}

创建一个具体模板(ConcreteClass)好儿子

public class ConcreteClass extends AblstractClass {//儿子不认可父亲的学习方法  考高分影响同学关系@Overridepublic void 学习() {System.out.println("60分万岁...");}//父亲给我爱情自由  一定好好谈恋爱@Overridepublic void 爱情() {System.out.println("肤白貌美大长腿...");}}

调用他们的人生

public class TestMain {public static void main(String[] args) {ConcreteClass cs  = new ConcreteClass();cs.人生();}}

结果输出

60分万岁...
从一而终
肤白貌美大长腿...

3. 模式在Servlet中的应用

3.1 自己实现一下

浏览器向服务端发送一个请求,常用请求方式有两种,get请求和post请求,这两种请求方式会导致请求参数在请求协议包(Http包)中的位置是不一样的,那么请求协议包中不同的内容到达服务端之后会有不同的对象进行处理,如请求头的内容由tomcat负责,请求体中的内容由request负责,所以此时,开发人员在拿到service()方法后考虑到它可以接受所有请求方式,因此会针对不同的请求方式封装不同的请求方法。

建一个OneServlet 继承GenericServlet,实现service()方法,需要重写里面的doPost和doGet方法。

public class OneServlet extends GenericServlet {@Overridepublic void service(ServletRequest req, ServletResponse arg1) throws ServletException, IOException {//1.从协议包【请求行】中来读取浏览器发送的请求方式HttpServletRequest request = (HttpServletRequest)req;//一般来说由父类修饰的对象由子类来修饰对象,目的就是功能扩充String method = request.getMethod();//POST  GETif("GET".equals(method)){doGet(req, arg1);}else if("POST".equals(method)){doPost(req, arg1);}    }//处理浏览器发送的post请求public void doPost(ServletRequest arg0, ServletResponse arg1){//这里面是doPost封装好的方法System.out.println("doPost is run....");}//处理浏览器发送的get请求public void doGet(ServletRequest arg0, ServletResponse arg1){//这里面是doPost封装好的方法System.out.println("doGet is run....");}}

现在开发人员面临的是,即需要做方法的实现,有需要考虑service()方法在何时调用。在实际开发过程中service()方法里面是一段重复性的代码,所有的servlet类实现中都需要写这么一段重复性的代码,这样重复的开发既增加工作量,又显得代码臃肿,降低了系统耦合度。模板方法设计模式就是来解决这个问题的。下面看一下怎么解决。

建立MyHttpServlet类(就是模板方法设计模式中的父类),继承GenericServlet类。

public  class MyHttpServlet extends GenericServlet {@Overridepublic void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {//控制子类中的doGet和doPost方法//1.从协议包【请求行】来读取浏览器发送的请求方式HttpServletRequest request = (HttpServletRequest)req;String method = request.getMethod();//POST  GETif("GET".equals(method)){doGet(req, res);//this.doGet()}else if("POST".equals(method)){doPost(req, res);}}public  void doPost(ServletRequest arg0, ServletResponse arg1){}public void doGet(ServletRequest arg0, ServletResponse arg1){}}

建立TwoServlet类,此时此刻开发人员不用去考虑何时调用doGet方法。当调用TwoServlet类的时候,tomcat一定是调用它的service()方法。

/*** Servlet implementation class TwoServlet*/
public class TwoServlet extends MyHttpServlet {//选择是接受doGet方法还是doPost方法@Overridepublic void doGet(ServletRequest arg0, ServletResponse arg1) {System.out.println("ThreeServlet doGet is run...");}}

测试代码localhost:8080/.../...

ThreeServlet doGet is run...

3.2 看HttpServlet源码

HttpServlet也是继承了GenericServlet ,跟踪找到Service()方法,发现有两个service()方法。

    //这个方法是从它的父类GenericServlet继承过来的@Overridepublic void service(ServletRequest req, ServletResponse res)throws ServletException, IOException{   HttpServletRequest  request;HttpServletResponse response;if (!(req instanceof HttpServletRequest &&res instanceof HttpServletResponse)) {throw new ServletException("non-HTTP request or response");}//分别对请求对象和响应对象做了类型强转。request = (HttpServletRequest) req;response = (HttpServletResponse) res;service(request, response);//调用的是自己声明的service方法,重载。}
}

进入到自己声明的service()方法

  protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException{String method = req.getMethod();//读取请求方式if (method.equals(METHOD_GET)) {//根据请求方式调用对应方法long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logicdoGet(req, resp);} else {long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);if (ifModifiedSince < lastModified) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be lessmaybeSetLastModified(resp, lastModified);doGet(req, resp);} else {resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}}} else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals(METHOD_POST)) {doPost(req, resp);} else if (method.equals(METHOD_PUT)) {doPut(req, resp);} else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {//// Note that this means NO servlet supports whatever// method was requested, anywhere on this server.//String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}

发现service方法没有使用final,这是因为如果使用final修饰,就彻底断绝了我们下游开发人员的开发,这样是降低了系统的灵活度。

设计模式是问题解决思想(办法),没有固定的命令搭配 。
如果我们自己可以有这样一些解决办法,那就是好的设计模式。

使用场景: tomcat中,生命周期中触发事件后,变更事件状态和相应动作处理

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

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

相关文章

【Linux进程】进程控制

目录 一、进程创建 1.2 fork函数初识 1.2 fork函数返回值 1.3 写时拷贝 1.4 fork常规用法 1.5 fork调用失败的原因 二、进程终止 2.1 进程退出场景 2.2 进程退出码 2.2.1 用strerror打印错误信息 2.2.2 errno全局变量 2.3 进程常见退出方法 2.3.1 进程正常退出 2…

阿里云国际站:密钥管理服务

文章目录 一、密钥管理服务的概念 二、密钥管理服务的功能 三、密钥管理服务的优势 一、密钥管理服务的概念 密钥管理服务KMS&#xff08;Key Management Service&#xff09;是您的一站式密钥管理和数据加密服务平台、一站式凭据安全管理平台&#xff0c;提供简单、可靠、…

国产双核DSP与 TI 的TMS320F28377 大PK

国产DSP&#xff0c;QX320F28377与 TI的 TMS320F28377 孰强孰弱

《QT从基础到进阶·二十六》绘制多个图形项(QGraphicsRectItem,QGraphicsLineItem,QGraphicsPolygonItem)

这个demo用QT实现了对多个图形项的绘制&#xff0c;包括矩形的绘制&#xff0c;直线的绘制和多边形的绘制&#xff0c;是之前一章中绘制矩形的增强版&#xff0c;之前一章节关于矩形的绘制可以参考&#xff1a;《QT从基础到进阶十五》用鼠标绘制矩形&#xff08;QGraphicsView、…

深入理解ElasticSearch分片

1. 路由计算 当索引一个文档的时候&#xff0c;文档会被存储到一个主分片中。 Elasticsearch 如何知道一个文档应该存放到哪个分片中呢&#xff1f;当我们创建文档时&#xff0c;它如何决定这个文档应当被存储在分片 1 还是分片 2 中呢&#xff1f;首先这肯定不会是随机的&…

uniapp 小程序 身份证 和人脸视频拍摄

使用前提&#xff1a; 已经在微信公众平台的用户隐私协议&#xff0c;已经选择配置“摄像头&#xff0c;录像”等权限 开发背景&#xff1a;客户需要使用带有拍摄边框的摄像头 &#xff0c;微信小程序的方法无法支持&#xff0c;使用camera修改 身份证正反面&#xff1a; <…

python读取excel,进行数据处理

一、准备python编译器 二、下载 pyexcel 库 pip install pyexcel-xls三、进行编码读取数据 import pyexcel# 读取Excel文件 成本中心字典 data pyexcel.get_array(file_name成本中心.xls)def hand():#打印数据#print(data)url f"INSERT INTO dst_base.sys_dict(p_…

OpenCV C++ 图像处理实战 ——《多二维码识别》

OpenCV C++ 图像处理实战 ——《多二维码识别》 一、结果演示二、zxing库配置2.1下载编译三、多二维码识别3.1 Method one3.1.1 源码3.2 Method two3.2.1 源码四、源码测试图像下载总结一、结果演示 </

无监督学习的集成方法:相似性矩阵的聚类

在机器学习中&#xff0c;术语Ensemble指的是并行组合多个模型&#xff0c;这个想法是利用群体的智慧&#xff0c;在给出的最终答案上形成更好的共识。 这种类型的方法已经在监督学习领域得到了广泛的研究和应用&#xff0c;特别是在分类问题上&#xff0c;像RandomForest这样…

RobotFramework常见问题如何解决 ?

附加-问题解决 1. 执行robot用例的时候提示WebDriverException: Message: invalid argument: cant kill an exited process 查看驱动的log是否是提示 如果是的话&#xff0c;参照第七步安装图形界面 2. jenkins启动后发现打不开jenkins页面的问题解决 打开jenkins页面提…

如何使用Cpolar+Tipask,在ubuntu系统上搭建一个私人问答网站

文章目录 前言2.Tipask网站搭建2.1 Tipask网站下载和安装2.2 Tipask网页测试2.3 cpolar的安装和注册 3. 本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3 Cpolar稳定隧道&#xff08;本地设置&#xff09; 4. 公网访问测试5. 结语 前…

compile: version “go1.19“ does not match go tool version “go1.18.1“

** 1 安装了新版本的go后 为什么go version 还是旧版本&#xff1f; ** 如果你已经按照上述步骤安装了新版本的 Go&#xff0c;但 go version 命令仍然显示旧版本&#xff0c;可能是因为你的环境变量设置不正确或未正确生效。你可以尝试以下方法来解决问题&#xff1a; 重新…