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 {
    
    //儿子不认可父亲的学习方法  考高分影响同学关系
    @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中,生命周期中触发事件后,变更事件状态和相应动作处理

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于springboot实现福聚苑社区团购平台系统项目【项目源码】计算机毕业设计

基于springboot实现福聚苑社区团购平台系统演示 Javar技术 Java是一种网络脚本语言&#xff0c;广泛运用于web应用开发&#xff0c;可以用来添加网页的格式动态效果&#xff0c;该语言不用进行预编译就直接运行&#xff0c;可以直接嵌入HTML语言中&#xff0c;写成js语言&…

最新有效rtsp/rtmp/hls地址长期维护

✍️作者简介&#xff1a;沫小北/码农小北&#xff08;专注于Android、Web、TCP/IP等技术方向&#xff09; &#x1f433;博客主页&#xff1a;沫小北/码农小北 开源中国、稀土掘金、51cto博客、博客园、知乎、简书、慕课网、CSDN &#x1f514;如果文章对您有一定的帮助请&…

Load-balanced-online-OJ-system 负载均衡的OJ系统项目

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 本项目Github地址 - Load-balanced-o…

Go,14周年[译]

国内的双十一购物狂欢已没有了当年的那种热闹与喧嚣&#xff0c;但大洋彼岸的Go团队却始终保持稳中有增的开发和语言演进节奏。今晨Go核心团队的Russ Cox[1]代表Go语言项目团队在Go官博上发表了《Fourteen Years of Go》[2]的博文&#xff0c;纪念Go语言开源14周年[3]&#xff…

证明串口是好的

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

牛客网上收藏题目总结及重写(C语言)(3)

每日一言 如果预计中的不幸没有发生的话&#xff0c;我们就会收获意外的喜悦。 --人生的智慧 题目BC84 错因&#xff1a;忘记要使用小数除法 代码 #include <stdio.h> int main() {int i 0;int n 0;scanf("%d",&n);double sum 0;for(i1;i<n;i){su…

如何用自然语言 5 分钟构建个人知识库应用?我的 GPTs builder 尝试

开发者的想象力闸门一旦打开&#xff0c;迎接我们的必然是目不暇接的 AI 应用浪潮冲击。 兴奋 早晨&#xff0c;我突然发现 ChatGPT 最新的 Create GPTs 功能可以用了。 这太让我意外了&#xff0c;没想到这么快。根据页面上的提示&#xff0c;我一直以为还得等上一周左右。于是…

跨境电商商城源码:实现多语言、多货币、多商户入驻的全面解决方案

随着全球电子商务的迅猛发展&#xff0c;越来越多的商家和消费者选择在跨境电商平台上进行交易。为了满足不同国家和地区的需求&#xff0c;多语言、多货币、多商户入驻已成为跨境电商平台的核心竞争力。本文将为您介绍如何通过跨境电商商城源码实现这些功能&#xff0c;帮助您…

qt系统自带的对话框

QMessageBox是静态成员函数可以直接通过类名进行访问 参数四是两个按钮的类型 第五个参数是回车默认选择的按键&#xff0c;该函数返回值是案件类型 其他标准对话框

react脚手架create-react-app创建react项目

1.全局安装 create-react-app winR/桌面目录下cmd进入终端页面 npm i -g create-react-app2.create-react app 初始化项目 create-react-app 项目名称项目初始化完成 运行项目 目录下cmd控制台输入 npm start然后打开本地服务运行项目查看

学会这10个Fluent仿真优化技巧,效率蹭蹭蹭

ANSYS Fluent 是计算流体动力学 (CFD) 仿真的强大工具&#xff0c;使工程师和科学家能够分析和预测各种应用中的流体行为。然而&#xff0c;运行模拟可能需要大量计算&#xff0c;因此优化设置对于在最短的时间内获得最准确的结果非常重要。 Fluent对电脑配置要求高&#xff1f…

服务号怎么升级订阅号

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;首先我们要看一下服务号和订阅号的主要区别。1、服务号推送的消息没有折叠&#xff0c;消息出现在聊天列表中&#xff0c;会像收到消息一样有提醒。而订阅号推送的消息是折叠的&#xff0c;“订阅号…

世微 升压恒压IC dc-dc转换器 充电器手持设备便携式产品 AP8660

AP8660是一款升压dc-dc转换器&#xff0c;内置MOS调节器&#xff0c;内部补偿&#xff0c;还可以最小6个外部组件&#xff0c;内部的软识启动功能可以降压涌入电流 AP8660 SOT23-6封装&#xff0c;可以为PCB提供节省空间 特点 可调输出&#xff0c;最高达到24W 内部固定PWM频…

CCF ChinaSoft 2023 论坛巡礼 | 生成式AI与软件自动化论坛

2023年CCF中国软件大会&#xff08;CCF ChinaSoft 2023&#xff09;由CCF主办&#xff0c;CCF系统软件专委会、形式化方法专委会、软件工程专委会以及复旦大学联合承办&#xff0c;将于2023年12月1-3日在上海国际会议中心举行。 本次大会主题是“智能化软件创新推动数字经济与社…

css实现鼠标悬停时元素的显示与隐藏

css实现鼠标悬停时元素的显示与隐藏 跟着B站黑马学习小兔鲜项目&#xff0c;有个点记录一下 就是当鼠标悬浮在商品列表上时&#xff0c;列表中的商品会显示出来&#xff0c;离开时&#xff0c;商品隐藏&#xff0c;如下&#xff1a; 感觉这个功能经常会遇到&#xff0c;但一直…

MATLAB中ginput函数用法

目录 语法 说明 示例 标识点和绘制坐标 返回用于选择坐标的按键 标识地理坐标区上的点 ginput函数的功能是标识坐标区坐标。 语法 [x,y] ginput(n) [x,y] ginput [x,y,button] ginput(___) 说明 [x,y] ginput(n) 可用于标识笛卡尔坐标区、极坐标区或地理坐标区内…

docker简易入门(极简,纯干货)

简介 Docker是一种容器化平台&#xff0c;它可以用来轻松地创建、部署和运行应用程序和服务。Docker使用容器技术来管理应用程序的运行环境&#xff0c;它将应用程序和服务打包到一个易于移植的容器中&#xff0c;然后在任何地方运行这个容器&#xff0c;无需担心不同环境之间…

一篇文章带你全面了解地埋一体机(雨水净化消毒一体机)

一、地埋一体机&#xff08;雨水净化消毒一体机&#xff09; 此设备集雨水过滤、消毒、排污于一体&#xff0c;通过六向阀手柄位置切换可实现过滤、消毒、反冲洗、排污等不同功能。 二、产品参数 三、产品功能介绍 地埋一体机由不锈钢壳体、砂缸、六向阀、消毒装置等部分组成。…

2023年CKA考试真题及注意事项

2023年CKA考试真题及注意事项 注意事项考试题目原题解析1.RBAC2.节点维护3.K8S组件升级 1.28.0升级到1.28.14.Etcd备份与恢复5.NetworkPolicy6.Service7.Ingress8.指定节点部署9.检查Node节点健康状态10.一个Pod多个容器11.监控Pod度量指标12.监控Pod日志13.PersistentVolumeCl…