模板模式(上):剖析模板模式在JDK、Servlet、JUnit等中的应用

news/2024/11/20 7:01:29/

今天,我们再学习另外一种行为型设计模式,模板模式。我们多次强调,绝大部分设计模式的原理和实现,都非常简单,难的是掌握应用场景,搞清楚能解决什么问题。模板模式也不例外。模板模式主要是用来解决复用扩展两个问题。

模板模式的原理与实现

模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。

        原理很简单,代码实现就更加简单,我写了一个示例代码,如下所示。templateMethod()函数定义为final,是为了避免子类重写它。method1()和method2()定义为abstract,是为了强迫子类去实现。不过,这些都不是必须的,在实际的项目开发中,模板模式的代码实现比较灵活,待会儿讲到应用场景的时候,我们会有具体的体现。

public abstract class AbstractClass {public final void templateMethod() {//...method1();//...method2();//...}protected abstract void method1();protected abstract void method2();
}public class ConcreteClass1 extends AbstractClass {@Overrideprotected void method1() {//...}@Overrideprotected void method2() {//...}
}public class ConcreteClass2 extends AbstractClass {@Overrideprotected void method1() {//...}@Overrideprotected void method2() {//...}
}AbstractClass demo = ConcreteClass1();
demo.templateMethod();

模板模式作用一:复用

模板模式把一个算法中不变的流程抽象到父类的方法templateMethod()中,可变的部分method1()和method2()留给子类实现。

1.Java InputStream

Java IO类库中,有很多类的设计用到了模板模式,比如InputStream、OutputStream、Reader、Writer。我们拿InputStream来举例说明一下。

我把InputStream部分相关代码贴在了下面。在代码中,read()函数是一个模板方法,定义了读取数据的整个流程,并且暴露了一个可以由子类来定制的抽象方法。不过这个方法也被命名为了read(),只是参数跟模板方法不同。

public abstract class InputStream implements Closeable {//...省略其他代码...public int read(byte b[], int off, int len) throws IOException {if (b == null) {throw new NullPointerException();} else if (off < 0 || len < 0 || len > b.length - off) {throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int c = read();if (c == -1) {return -1;}b[off] = (byte)c;int i = 1;try {for (; i < len ; i++) {c = read();if (c == -1) {break;}b[off + i] = (byte)c;}} catch (IOException ee) {}return i;}public abstract int read() throws IOException;
}public class ByteArrayInputStream extends InputStream {//...省略其他代码...@Overridepublic synchronized int read() {return (pos < count) ? (buf[pos++] & 0xff) : -1;}
}

模板模式作用二:扩展

模板模式常用在框架的开发中,让框架用户可以在不修改框架源码的情况下,定制化框架的功能。我们通过Java Servlet来解释一下。

1.Java Servlet

对于Java Web项目开发来说,常用的开发框架是SpringMVC。利用它,我们只需要关注业务代码的编写,底层的原理几乎不会涉及。但是,如果我们抛开这些高级框架来开发Web项目,必然会用到Servlet。实际上,使用比较底层的Servlet来开发Web项目也不难。我们只需要定义一个继承HttpServlet的类,并且重写其中的doGet()或doPost()方法来分别处理get和post请求。具体的代码示例如下所示:

@WebServlet("/hello")
public class HelloServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doPost(req, resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("Hello World.");}
}

当我们在浏览器中输入网址(比如,http://127.0.0.1:8080/hello )的时候,Servlet容器会接收到相应的请求,并且根据URL和Servlet之间的映射关系,找到相应的Servlet(HelloServlet),然后执行它的service()方法。service()方法定义在父类HttpServlet中,它会调用doGet()或doPost()方法,然后输出数据(“Hello world”)到网页

我们现在来看,HttpServlet的service()函数长什么样子。

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);
}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 {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);}
}

总结和反思:

  • 模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些步骤。这里的“算法”,我们可以理解为广义上的“业务逻辑”,并不特指数据结构和算法中的“算法”。这里的算法骨架就是“模板”,包含算法骨架的方法就是“模板方法”,这也是模板方法模式名字的由来。
  • 在模板模式经典的实现中,模板方法定义为final,可以避免被子类重写。需要子类重写的方法定义为abstract,可以强迫子类去实现。不过,在实际项目开发中,模板模式的实现比较灵活,以上两点都不是必须的。

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

相关文章

显卡驱动的作用(本质作用)

确切资料表明显卡不需要驱动也可以进行显示&#xff0c;只需要将显示的内容存到对应的显存地址就可以&#xff08;通过cpu直接或者间接的硬连线实现&#xff09;。也就是说单纯的显示像素的话不需要使用显卡驱动&#xff0c;但是单纯的显示像素甚至某些情况下都不需要显卡&…

ubantu 安装显卡

电脑的配置如下&#xff1a; 在安装Ubuntu的时候勾选了默认安装的开源显卡驱动&#xff0c;但是打开发现问题太多&#xff0c;而且很难知道显卡到底有没有起作用&#xff0c;因此决定自己安装显卡驱动。 修复重启时报告的 AMD 核显问题 在每次重启或者关机的时候&#xff0c…

JVM理论(四)运行时数据区--堆/方法区

堆(heap) 堆内存逻辑上分为三部分 一个JVM实例只存在一个堆内存,JVM启动时创建堆区&#xff0c;通常情况下也是最大的内存空间&#xff0c;几乎所有的对象实例都要在堆中分配内存&#xff0c;所以堆也是垃圾回收的重点区域堆是被所有线程共享的,在堆里面也可以划分线程私有的缓…

认识企业级定时任务Quartz

文章目录 前言一、实现一个Quartz的小案例1.创建一个maven项目2.添加Quartz依赖3.创建一个配置文件配置Quartz信息4.创建一个Job类继承Job接口5.编写主方法逻辑进行测试6.测试运行结果 二、Job和JobDetail总结 前言 目前仍有大部分企业仍在使用Quartz这种定时任务框架&#xf…

ssd5和ssd6的区别

容量不同 组装电脑怎么搭配更适合 这些点很重要看过你就懂了 http://www.adiannao.cn/du 1、ssd5&#xff1a;指的是SSD 540S 系列&#xff0c;产品容量为180GB。 2、ssd6&#xff1a;指的SSD 600P系列&#xff0c;产品容量为128GB。 二、性能不同 1、ssd5&#xff1a;顺序读…

promise规范及应用

##promise解析 *啥是异步? //异步执行let count 1let timer setTimeout(function () {countconsole.log(in, count);}, 1000);console.log(out);// out>1000>in//循环执行let count 1let timer setInterval(function () {countconsole.log(in, count);}, 1000);con…

排序算法笔记--摩尔投票算法

摩尔投票算法 摩尔投票算法是一种用于在数组中查找出现次数超过一半的元素的有效算法。算法的核心思想是利用候选元素和计数器进行投票&#xff0c;通过消除不同元素之间的抵消来找到出现次数超过一半的元素。 算法原理 如果数组中存在一个出现次数超过一半的元素&#xff0…

10kv电压互感器型号_高压互感器型号含义

1 &#xff0e;互感器的分类 (1) 按用途分为&#xff1a;电压互感器和电流互感器&#xff1b; (2) 按精度等级分为&#xff1a;工业用互感器 (0.2 、 0.5 、 3 级及以下&#xff0c;保护和控制用 ) 和标准互感器 (0.1 级以上 ) 。 2 &#xff0e;国产互感器型号的含义 (1) 电压…