模版方法模式在 JDK 及 spring 源码中的引用

news2024/11/25 21:28:00

模版方法模式

模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。

更多有关于模版方法模式的介绍详见:https://refactoringguru.cn/design-patterns/template-method

模版方法模式在 JDK 源码中的引用

  1. 定义 List 接口,定义一些规范。
  2. 抽象类 AbstractList 实现 List 接口,写一些通用的实现。
  3. 子类 ArrayList, LinkedList 继承抽象类 AbstractList,写自己的具体实现。
    在这里插入图片描述

List 接口

public interface List<E> extends Collection<E> {
    int size();
    boolean isEmpty();
    boolean contains(Object o);
    E get(int index);
    E set(int index, E element);
    void add(int index, E element);
    E remove(int index);
    // ...... 省略其他内容
}

List 接口的部分内容如上所示,定义了一些列表容器的规范,比如:获取容器中元素个数、是否为空、是否包含某个元素、获取某个索引位置对应元素、移除元素等方法。

AbstractList

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
    public boolean add(E e) {
        add(size(), e);
        return true;
    }

    abstract public E get(int index);
    
    public E remove(int index) {
        throw new UnsupportedOperationException();
    }
    
    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }
    
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }
    // ...... 省略其他内容
}

ArrayList

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;
    private static final int DEFAULT_CAPACITY = 10;
    private static final Object[] EMPTY_ELEMENTDATA = {};
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    transient Object[] elementData; // non-private to simplify nested class access
    private int size;
    
    public int size() {
        return size;
    }

    public boolean isEmpty() {
        return size == 0;
    }
    
    public boolean contains(Object o) {
        return indexOf(o) >= 0;
    }
    
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }
    
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

    public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }
    
    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
	// ...... 省略其他内容
}

模板方法模式在 spring 源码中的应用

  1. 定义 Servlet 接口,定义一些规范。
  2. 抽象类 GenericServlet 实现 Servlet 接口,写一些通用的实现。
  3. 抽象类 HttpServlet 继承 GenericServlet 类,写一些有关 Http 请求的通用实现。
  4. 自定义子类继承抽象类 HttpServlet ,根据自己的业务处理 http 请求。
    在这里插入图片描述

Servlet

public interface Servlet {
	public void init(ServletConfig config) throws ServletException;
	public ServletConfig getServletConfig();
	public void service(ServletRequest req, ServletResponse res)
	            throws ServletException, IOException;
	public String getServletInfo();
	public void destroy();
}

GenericServlet

将 ServletConfig 由局部变量变为全局变量

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable {
    private static final long serialVersionUID = 1L;
    private transient ServletConfig config;
    
    public GenericServlet() {
        // NOOP
    }
    @Override
    public void destroy() {
        // NOOP by default
    }
	@Override
    public ServletContext getServletContext() {
        return getServletConfig().getServletContext();
    }
	@Override
    public ServletConfig getServletConfig() {
        return config;
    }
    // 省略其他代码......
}

HttpServlet

重写核心的 service 方法,完成通用逻辑的编写:根据请求方式调用相应的 doGet, doPost 等方法。
定义 doGet, doPost 等方法,让子类重写。如果请求方式为 GET,但子类没有重写 doGet 方法,则会执行父类(即该类 HttpServlet)的 doGet 方法:通用逻辑为返回 400 或 405 异常。

public abstract class HttpServlet extends GenericServlet {
	// ...... 省略部分代码
  	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

    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;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // 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);
        }
    }
    // 省略其他代码......
}

自定义类 HelloServlet

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        Writer writer = resp.getWriter();
        writer.write("hello SimpleServletHandlerAdapter!");
        writer.flush();
    }
}

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

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

相关文章

【4】tf实现神经网络模型

1 M-P神经元与神经网络前向传输 1.1 训练单个神经元 一个含有两个输入的神经元&#xff0c;指定一个输入x1x21,期望y能输出0.3。要求不断的输入x1x21,然后不断的训练权重w与偏置b值&#xff0c;训练一万次后&#xff0c;再次输入x1与x2输出y的值是否为0.3 # 导入TensorFlow库…

Linux 进程的睡眠和唤醒详解

概要 在Linux中&#xff0c;仅等待CPU时间的进程称为就绪进程&#xff0c;它们被放置在一个运行队列中&#xff0c;一个就绪进程的状 态标志位为 TASK_RUNNING。一旦一个运行中的进程时间片用完&#xff0c; Linux 内核的调度器会剥夺这个进程对CPU的控制权&#xff0c;并且从…

QGIS实现tiff影像栅格数据切片教程

实现栅格切片的方式有很多种,geoserver可以,qgis可以。自己写代码也可以,方式非常多。这篇文章介绍一下如何使用QGIS实现栅格切片。 首先我们要去下载一个qgis软件。下载地址如下: Welcome to the QGIS project! 随后我们打开软件,然后把要切片的栅格数据(tiff文件或者…

【Python 随练】逆序打印数字

题目&#xff1a; 给一个不多于 5 位的正整数&#xff0c;要求&#xff1a; 一、求它是几位数&#xff0c; 二、逆序打印出各位数字。 简介&#xff1a; 在本篇博客中&#xff0c;我们将解决一个关于正整数的问题。根据题目要求&#xff0c;我们需要判断给定的正整数是几位数…

你的仓库VS别人家的仓库,有什么不同?

导读&#xff1a; 近年来&#xff0c;随着新技术的蓬勃发展&#xff0c;企业的仓储管理水平大大提高&#xff0c;PDA、RFID、AGV、立体仓库、智能分拣线等各项新技术的应用层出不穷。然而&#xff0c;着眼于制造型企业&#xff0c;却发现仍有许多仓库处在比较原始、传统、粗放…

[译] DeepSpeed:所有人都能用的超大规模模型训练工具

我们于今年 2 月份发布了 DeepSpeed。这是一个开源深度学习训练优化库&#xff0c;其中包含的一个新的显存优化技术—— ZeRO&#xff08;零冗余优化器&#xff09;&#xff0c;通过扩大规模&#xff0c;提升速度&#xff0c;控制成本&#xff0c;提升可用性&#xff0c;极大地…

如何绘制甘特图?这个软件来帮你

最好用的甘特图软件是什么&#xff1f;先看效果&#xff0c;再放教程&#xff1a; 这是大家用的比较多的excel做出的甘特图&#xff1a; 这是我做的动态甘特图&#xff1a; 两种方法&#xff0c;分享给大家&#xff0c;按需选择即可。 第一种&#xff1a;用Excel制作甘特图 用…

nx安装cuda与cudnn

本文参考 Jetson xavier nx 安装CUDA10.2&#xff0c;和cudnn8.0_jetson安装cuda_三羊木木的博客-CSDN博客 NX安装cuda和cudnn_nx cuda_viatea的博客-CSDN博客 进入nx系统后&#xff0c;输入 sudo apt-get update 更新源 目录 1 cuda 2 cudnn 1 cuda sudo apt-get ins…

如何注册GitHub账号

一、注册GitHub账号 1、浏览器URL中输入地址: https://github.com/ 2、跳转至GitHub官网 3、点击右上角sign up按钮 4、填写注册信息 这个大意是产品更新时消息会通过邮箱发给你&#xff0c;根据需求选择y or n 5、验证账户 有的小伙伴会出现错误信息 Unable to verify you…

考研算法28天:优化版插入排序(折半插入排序)【二分,插入排序】

算法介绍 算法介绍就是说我们原先写的插入排序的这段代码 for(int i1;i<n;i){//开始向前遍历&#xff0c;如果发现前面的元素比//x大的话&#xff0c;就将前面的元素放到x的后面int x q[i],ji;while( j && q[j-1]>x ){q[j] q[j-1];j--;}q[j] x;}我们里面那层…

Redis_6.2.12下载及安装(CentOS7)

文章目录 Redis安装-CentOS71、下载地址2、下载安装流程2.1 安装依赖2.2 官网下载tar包2.3 进入解压目录并编译2.4 启动Redis服务2.5 全局使用redis-cli、redis-server2.6 防火墙开启6379端口查看防火墙状态以及启动、关闭配置firewalld-cmd开启防火墙端口 3、设置开机自动启动…

SpringBoot集成百度人脸识别

SpringBoot集成百度人脸识别 1、概述2、账号申请账号登录注册创建应用 3、抽取模板工具AipFacePropertiesAipFaceTemplateapplication.yml 4、测试 ​ 人脸识别&#xff08;Face Recognition&#xff09;基于图像或视频中的人脸检测、分析和比对技术&#xff0c;提供对您已获授…

如何使用 SpringBoot 创建 RESTful API

如何使用 SpringBoot 创建 RESTful API SpringBoot是一个流行的Java框架&#xff0c;它可以帮助我们快速构建应用程序。其中&#xff0c;创建RESTful API是SpringBoot的常见用例之一。在本文中&#xff0c;我们将介绍如何使用SpringBoot创建RESTful API。 什么是RESTful API …

不同业务场景、不同数据类型,对应亚马逊云科技不同数据库服务

小小的改变&#xff0c;标志一个新时代的全面开启&#xff0c;一个数据库的云原生时代。前不久&#xff0c;Gartner公布了一组数据&#xff0c;引起了不小的讨论度。在2022年全球数据库管理系统的市场份额排名中&#xff0c;作为纯云厂商的亚马逊云科技&#xff0c;超越了老牌传…

电脑如何录屏?3个方法教您win10电脑怎么录屏!

案例&#xff1a;有时手机录屏满足不了我的录制需求&#xff0c;我需要在电脑上录屏&#xff0c;但我对电脑不是特别熟悉&#xff0c;不知道如何在电脑上录屏。 很多小伙伴想在电脑上录制视频&#xff0c;但又不知道如何操作。win10电脑录屏怎么录&#xff1f;有没有简单且详细…

趋势分享 | 多云时代数据安全面临的挑战

IT 和数据管理研究和咨询公司 EMA&#xff08;Enterprise Management Associates&#xff09;早前发布的一份《多云环境下的数据安全》&#xff08;Data Security in a Multi-Cloud World&#xff09;研究报告&#xff0c;调查了来自十个以上不同行业垂直领域、公司规模在 500 …

Kotlin对象和单例模式:探索这种强大设计模式的好处

Kotlin对象和单例模式&#xff1a;探索这种强大设计模式的好处 在Kotlin中&#xff0c;使用关键字"object"来定义一个单例对象。所谓单例对象&#xff0c;就是在整个应用程序中只有一个实例存在。简单来说&#xff0c;就好像只有一个蜘蛛侠一样&#xff0c;不可能同时…

群晖NAS遇到断电如何自动关机

群晖NAS遇到断电时如何自动关机 前置条件实现功能的想法具体实施的步骤开启群晖Linux的SSH登陆安装Putty或是Xshell远程登陆上群晖创建计划任务 前置条件 需要一台UPS&#xff08;品牌功能不限&#xff0c;只需续航5分钟以上就可以&#xff09; 实现功能的想法 通过监控网卡…

基于Python+Django+mysql+html图书管理系统

基于PythonDjangomysqlhtml图书管理系统 一、系统介绍二、功能展示1.用户登陆2.用户注册3.密码修改4.图书查询5.图书添加6.图书修改7.图书删除 三、其它系统四、获取源码 一、系统介绍 该系统实现了 用户登陆、用户注册、密码修改、图书查询、图书添加&#xff0c;图书修改、图…

一场场网络时代的“墨攻”

编辑&#xff1a;阿冒 设计&#xff1a;沐由 公输般为楚造云梯之械成&#xff0c;将以攻宋。子墨子闻之&#xff0c;起于鲁&#xff0c;行十日十夜&#xff0c;而至于郢&#xff0c;见公输般。 子墨子解带为城&#xff0c;以牒为械&#xff0c;公输般九设攻城之机变&#xff0c…