模板模式的原理与实现
模板方法模式在一个方法中定义一个算法骨架,并将某些步骤推迟到子类 中实现。模板方法模式可以让子类在不改变算法整体结构的情况下,重新定义算法中的某些 步骤。
一个具体的例子如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| public abstract class AbstractClass { public final void templateMethod() { method1(); method2(); } protected abstract void method1(); protected abstract void method2(); } public class ConcreteClass1 extends AbstractClass { @Override protected void method1() { } @Override protected void method2() { } } public class ConcreteClass2 extends AbstractClass { @Override protected void method1() { } @Override protected void method2() { } } AbstractClass demo = ConcreteClass1(); demo.templateMethod();
|
模板模式作用一:复用
模板模式把一个算法中不变的流程抽象到父类的模板方法 templateMethod() 中,将可变的部分 method1()、method2() 留给子类 ContreteClass1 和 ContreteClass2 来实现。 所有的子类都可以复用父类中模板方法定义的流程代码。
模板模式作用二:扩展
模板模式的第二大作用的是扩展。这里所说的扩展,并不是指代码的扩展性,而是指框架的 扩展性,有点类似我们之前讲到的控制反转。基于这个作用,模板模式常用在框架的开发中,让框架用户可以在不修改框架源码的情况下,定制化框架的功能。
1.Java Servlet
在平时开发中,如果我们使用Servlet进行web开发,那么就需要继承 HttpServlet,并且重写其中的 doGet() 或 doPost() 方 法,来分别处理 get 和 post 请求。
1 2 3 4 5 6 7 8 9 10
| public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Expection { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throw Expection { resp.getWriter().write("Hello World."); } }
|
除此之外,我们还需要在配置文件 web.xml 中做如下配置。Tomcat、Jetty 等 Servlet 容 器在启动的时候,会自动加载这个配置文件中的 URL 和 Servlet 之间的映射关系。
1 2 3 4 5 6 7 8
| <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.xzg.cd.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
|
当我们在浏览器中输入网址(比如,http://127.0.0.1:8080/hello )的时候,Servlet 容 器会接收到相应的请求,并且根据 URL 和 Servlet 之间的映射关系,找到相应的 Servlet(HelloServlet),然后执行它的 service() 方法。service() 方法定义在父类 HttpServlet 中,它会调用 doGet() 或 doPost() 方法,然后输出数据(“Hello world”)到网页。
以下是service方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| 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) { doGet(req, resp); } else { long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); if (ifModifiedSince < lastModified) { 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 { 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); } }
|
从上面的代码中我们可以看出,HttpServlet 的 service() 方法就是一个模板方法,它实现 了整个 HTTP 请求的执行流程,doGet()、doPost() 是模板中可以由子类来定制的部分。
参考
《设计模式之美》