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

news2024/12/29 11:00:20

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 {
    
    //儿子不认可父亲的学习方法  考高分影响同学关系
    @Override
    public void 学习() {
        System.out.println("60分万岁...");
    }
    
    //父亲给我爱情自由  一定好好谈恋爱
    @Override
    public 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 {

    @Override
    public void service(ServletRequest req, ServletResponse arg1) throws ServletException, IOException {
        
        
                //1.从协议包【请求行】中来读取浏览器发送的请求方式
                HttpServletRequest request = (HttpServletRequest)req;//一般来说由父类修饰的对象由子类来修饰对象,目的就是功能扩充
                String method = request.getMethod();//POST  GET
                if("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 {

    @Override
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        //控制子类中的doGet和doPost方法
        //1.从协议包【请求行】来读取浏览器发送的请求方式
        HttpServletRequest request = (HttpServletRequest)req;
        String method = request.getMethod();//POST  GET
        if("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方法
    
    @Override
    public 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继承过来的
    @Override
    public 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 logic
                doGet(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 less
                    maybeSetLastModified(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.coloradmin.cn/o/1202866.html

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

相关文章

如何实现公网远程访问本地OpenGauss数据库【内网穿透】

文章目录 前言1. Linux 安装 openGauss2. Linux 安装cpolar3. 创建openGauss主节点端口号公网地址4. 远程连接openGauss5. 固定连接TCP公网地址6. 固定地址连接测试 前言 openGauss是一款开源关系型数据库管理系统&#xff0c;采用木兰宽松许可证v2发行。openGauss内核深度融合…

芸鹰蓬飞:抖音投流以后还有自然流量吗?

随着抖音平台的普及&#xff0c;企业和个人纷纷加入到这个短视频的热潮中。然而&#xff0c;一旦投入抖音投流&#xff0c;是否还能依赖自然流量&#xff1f;这是许多用户和品牌关心的问题。本文将深入剖析这一话题&#xff0c;探讨抖音投流与自然流量之间的关系。 一、抖音投…

SpringBoot项目中ModelMapper配置以及使用

这里总结一下ModelMapper的使用方式&#xff0c;供大家参考 前言 项目中对象与对象赋值转换使用的频率非常的高&#xff0c;比如数据库表实体对象(Entity)与业务类对象(Model)之间的赋值传递&#xff0c;或者模型对象&#xff08;Model&#xff09;与视图对象&#xff08;View…

报错:Parsing error: No Babel config file detected...的解决方案

报错&#xff1a;Parsing error: No Babel config file detected for E:\前端学习资料\9.vue基础\class\day03\02-源代码\01-component\vue.config.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the confi…

EasyPOI实现excel文件导出

EasyPOI真的是一款非常好用的文件导出工具&#xff0c;相较于传统的一行一列的数据导出&#xff0c;这种以实体类绑定生成的方式真的非常方便&#xff0c;也希望大家能够了解、掌握其使用方法&#xff0c;下面就用一个实例来简单介绍一下EasyPOI的使用。 1.导入依赖 <!-- e…

Autosar模块介绍:Memory_3(MemIf-内存接口抽象)

上一篇 | 返回主目录 | 下一篇 Autosar模块介绍&#xff1a;Memory_3(MemIf-内存接口抽象 1 基本术语解释2 MemIf组成结构图 1 基本术语解释 编号缩写原文解释1(Logical) Block——可单独寻址的连续内存区域&#xff08;即&#xff0c;用于读、写、擦除、比较等操作&#xff…

深度学习 python opencv 实现人脸年龄性别识别 计算机竞赛

文章目录 0 前言1 项目课题介绍2 关键技术2.1 卷积神经网络2.2 卷积层2.3 池化层2.4 激活函数&#xff1a;2.5 全连接层 3 使用tensorflow中keras模块实现卷积神经网络4 Keras介绍4.1 Keras深度学习模型4.2 Keras中重要的预定义对象4.3 Keras的网络层构造 5 数据集处理训练5.1 …

如何用python生成动态随机验证码图片

相信大部分小伙伴在登录注册页面都看到过这样的验证码图片&#xff1a; 今天就带大家用实现一波这种验证码图片的生成&#xff0c;这在Django开发中可以拿来即用~ 1. 首先导入必要的库&#xff1a; import random from PIL import Image, ImageDraw, ImageFont, ImageFilter…

Vatee万腾科技决策力的引领创新:Vatee数字化视野的崭新天地

在数字时代的激烈竞争中&#xff0c;Vatee万腾以其科技决策力的引领&#xff0c;开创了数字化视野的崭新天地。这并不仅仅是一场技术的飞跃&#xff0c;更是一次对未来的深刻洞察和引领创新的勇敢实践。 Vatee万腾的科技决策力不仅仅停留在数据分析和算法的运用&#xff0c;更是…

reticulate | R-python调用 | 安装及配置 | conda文件配置

reticulate | R-python安装及配置 | conda文件配置 1. 基础知识2. 安装reticulate from CRAN3. 包含了用于Python和R之间协同操作的全套工具&#xff0c;在R和Rstudio中均可使用4. 配置python环境4.1 4种环境配置方式4.2 miniconda 环境install_miniconda()报错一install_minic…

设计模式之原型模式(Prototype)

原型模式 如果已经有一个对象了&#xff0c;你想创建一个对象&#xff0c;而且对象里面的属性和已经存在的对象的属性差不多&#xff0c;就可以使用clone方法 克隆一个出来 实现原型模式需要实现标记型接口Cloneable -->标记型接口 : 里面没有需要实现的方法(空接口) 一般…

双十一钜惠!三门不可多得的HarmonyOS学习教程

今年双十一&#xff0c;各大商城优惠不断。这里介绍三门不可多得的HarmonyOS学习教程&#xff0c;都有非常大的折扣优惠。 《鸿蒙HarmonyOS手机应用开发实战》 《鸿蒙HarmonyOS手机应用开发实战》是由清华大学出版社出版的。 目前当当是“7.56折”&#xff1a;http://produc…

照片放大软件 Topaz Gigapixel AI mac中文版简介

Topaz Gigapixel AI mac是一款使用人工智能功能扩展图像的桌面应用程序&#xff0c;同时添加自然细节以获得惊人的效果。使用深度学习技术&#xff0c;A.I.Gigapixel™可以放大图像并填写其他调整大小的产品遗漏的细节&#xff0c;使用A.I.Gigapixel™&#xff0c;您可以裁剪照…

Vatee万腾外汇数字化策略:Vatee科技决策力的未来引领

在外汇市场&#xff0c;Vatee万腾通过其前瞻性的外汇数字化策略&#xff0c;正引领着科技决策的未来。这一数字化策略的崭新愿景为投资者提供了更智慧、更高效的外汇投资体验&#xff0c;成为科技决策领域的翘楚。 Vatee万腾的外汇数字化策略是科技决策力未来引领的典范。通过运…

14.求n!和1!+2!+...+20!和2^1+2^2+……++2^20和2^1+2^3+……++2^19

文章目录 前言一、题目描述 二、题目分析 三、解题 程序运行代码 四、举一反三一、题目描述&#xff1a;求1&#xff01;2&#xff01;...20! 二、题目分析 三、解题 程序运行代码1程序运行代码2 一、题目描述&#xff1a;求求2^1^2^2^……2^20^二、解题 程序运行代码 一、题目…

将ChatGPT集成在AR中,Snap玩出了新花样!

著名社交媒体平台Snap在官网宣布&#xff0c;在最新的AR开发平台Lens Studio 5.0版本中&#xff0c;集成ChatGPT功能。 在ChatGPT的帮助下&#xff0c;开发人员可以创建更多有趣、科普、对话、创意的Snapchat镜头&#xff0c;例如&#xff0c;通过ChatGPT创建无限测验和随机生…

燃气管网监测系统|全面保障燃气安全

根据新华日报的报道&#xff0c;2023年上半年&#xff0c;我国共发生了294起燃气事故&#xff0c;造成了57人死亡和190人受伤&#xff0c;燃气事故的发生原因有很多&#xff0c;其中涉及到燃气泄漏、设备故障等因素。因此&#xff0c;加强燃气安全管理&#xff0c;提高城市的安…

祝贺莱佛士学生获得SDC国际设计大赛新加坡赛区冠军

染色师和调色师协会国际设计大赛&#xff08;SDC International Design Competition&#xff0c;简称SDC国际设计大赛&#xff09;由英国染色家协会&#xff08;Society of Dyers and Colourists&#xff0c;简称SDC&#xff09;举办。 SDC成立于1884年&#xff0c;是国际上最…

基于 PostgreSQL 构建 AI 电商产品图片相似度搜索方案

在这篇文章中&#xff0c;将介绍如何基于向量数据库&#xff0c;构建一个电商产品图片目录的向量相似度查询解决方案。我们将通过 Amazon SageMaker、pgvector 向量数据库扩展插件、小型语言模型助力 AI 图片搜索能力&#xff0c;从而在产品目录中查找到最符合条件的产品&#…

证明串口是好的

前提&#xff1a;客户返回来一个pad&#xff0c;说串口不好用&#xff0c;售后让研发确定一下串口好不好用。 pad的串口是usb口&#xff08;不知道这样说对不对&#xff09;&#xff0c;然后就一个“usb--9针”的线。 要确定串口好不好&#xff0c;首先要从电脑发数据给pad&a…