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

news/2024/10/17 18:13:15/

模版方法模式

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

更多有关于模版方法模式的介绍详见: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 accessprivate 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 workreturn 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}@Overridepublic void destroy() {// NOOP by default}@Overridepublic ServletContext getServletContext() {return getServletConfig().getServletContext();}@Overridepublic 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 logicdoGet(req, resp);} else {long ifModifiedSince;try {ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);} catch (IllegalArgumentException iae) {// Invalid date header - proceed as if none was setifModifiedSince = -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 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);}}// 省略其他代码......
}

自定义类 HelloServlet

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

http://www.ppmy.cn/news/534977.html

相关文章

小米note3刷机-从miui12刷回miui9

小米note3刷机-从miui12刷回miui9 文章目录 小米note3刷机-从miui12刷回miui9解除BL锁进入开发者模式遇到的问题解决BootLoader无法连接电脑的问题 导包 3月份原本想买一部小米6回来刷机,结果发现小米6的二手价格有一点点high。然后就选了一个 大平版 小米note3 但是直到昨天…

苹果电脑mac或苹果手机如何下载b站视频到电脑或手机本地?

苹果电脑macbook怎么下载b站视频到电脑本地&#xff0c;今天给大家分享一个代下载的方法&#xff1a; 1、搜索&#xff1a; 小白兔视频格式在线转换 2、联系客服。 3、转换好后&#xff0c;我们把转换的视频下载到电脑里&#xff0c;就可以看到视频已经是MP4格式了。

洛达AB1562M 悦虎2代AB1562M_V130.1.1.151固件

洛达AB1562M 悦虎2代AB1562M_V130.1.1.151固件 AB1562M_V130.1.1.151 最新1562M固件AB1562M_V130.1.1.151 适用于华强北苹果2代AirPods悦虎&#xff08;小猪佩奇千万别刷了&#xff09; 我升级了暂时没发现异样。 升级教程就不发了。B站很多UP都发过。 唯独151固件没人发&…

如何区分IPEX一代/二代/三代/四代/五代

1&#xff0c;参考&#xff1a;http://www.juncoax.com/QA-1?article_id1321 2&#xff0c;参考&#xff1a;https://blog.csdn.net/qlexcel/article/details/116718808

苹果2代3G版本越狱+解锁到4.2.1

越狱和激活&#xff1a;苹果2代3G版本的机器用redsn0w_win_0.9.6b4.rar升级到4.2.1基带会变化&#xff0c;变成5.14的&#xff0c;所以必须继续升级&#xff0c;用红雪redsn0w_win_0.9.6b5.rar继续刷机&#xff0c;刷成IPAD版本的&#xff0c;使其基带变成6.15的版本&#xff0…

汽车巨头不愿被 “羞辱”,苹果造车重回代工模式

本文转载自IT之家&#xff0c;苹果公司原本希望与现有汽车制造商合作造车&#xff0c;但是汽车厂商不愿支持这个具有颠覆能力的新对手&#xff0c;让他们为苹果代工汽车就好比让三星为苹果生产 iPhone。 彭博社刊文称&#xff0c;绕了一圈后&#xff0c;苹果造车更有可能重回 …

【送给读者】全新苹果 AirPods,包邮送一套!

为回馈长期以来科创人读者对本栏目的关注支持&#xff0c;本周小编联合了计算机领域八位高质量原创号主一起为大家送出一套 全新苹果AirPods 2代。 以下推荐的公号原创率都很高&#xff0c;均为个人IP号&#xff0c;有些小伙伴应该已经关注部分公号。 本次抽奖采用第三方抽奖小…

黑客或可完全控制设备,苹果紧急发布补丁!

8月20日&#xff0c;苹果公司报告了一个重大的安全漏洞&#xff0c;这些漏洞可能会让潜在的攻击者入侵用户设备、获得管理权限甚至完全控制设备并运行其中的应用软件。 据介绍&#xff0c;受本次漏洞影响的设备涵盖了几乎所有的苹果产品。其中手机包括iPhone 6S及以后的型号&a…