本篇文章主要介绍模板方法模式.
模板方法模式: 模板方法模式是类的行为模式. 准备一个抽象类, 将部分逻辑以具体方法以及具体构造函数的形式实现, 然后声明一些抽象方法来迫使子类实现剩余的逻辑. 不同的子类可以以不同的方式实现这些抽象方法, 从而度剩余的逻辑有不同的实现. 这就是模板方法模式的用意.
我们先看下结构图.
AbstractClass 是抽象类, 其实也就是一抽象模板, 定义并实现了一个模板方法. 这个模板方法一般是一个具体方法, 它给出一个顶级逻辑的骨架, 而逻辑的组成步骤在相应的抽象操作中, 推迟到子类实现. 顶级逻辑也有可能调用一些具体方法.
下面我们以大话设计模式一书中的试卷例子来简单实现以下模板方法模式.
首先是试卷父类.
- package com.lwx.template_method;
- /**
- * Created with IntelliJ IDEA.
- * Description: 考题试卷
- * User: lwx
- * Date: 2019-03-11
- * Time: 22:39
- */
- public abstract class TestPaper {
- private void testQuestion1(){
- System.out.println("杨过得到, 后来给了郭靖, 炼成倚天剑, 屠龙刀的玄铁可能是: A. 球磨铸铁 B. 马口铁 C. 高速合金钢 D. 碳素纤维");
- System.out.println("学生答案:" + answer1());
- }
- private void testQuestion2(){
- System.out.println("杨过, 程英, 陆无双铲除了情花造成: A. 使这种植物不再害人 B. 使一种珍稀物种灭绝 C. 破坏了那个生物圈的生态平衡 D. 造成该地区沙漠化");
- System.out.println("学生答案:" + answer2());
- }
- private void testQuestion3(){
- System.out.println("蓝凤凰致使华山师徒, 核谷六仙呕吐不止, 如果你是大夫, 会给他们开什么药: A. 阿匹斯林 B. 牛黄解毒片" +
- "C. 氟哌酸 D. 让他们喝大量的生牛奶 E. 以上全不对");
- System.out.println("学生答案:" + answer3());
- }
- public void answerQuestion() {
- testQuestion1();
- testQuestion2();
- testQuestion3();
- }
- abstract String answer1();
- abstract String answer2();
- abstract String answer3();
- }
将答案写成抽象方法, 让子类去实现.
然后看下学生 A 子类.
- package com.lwx.template_method;
- /**
- * Created with IntelliJ IDEA.
- * Description:
- * User: lwx
- * Date: 2019-03-11
- * Time: 22:49
- */
- public class StudentAPaper extends TestPaper {
- @Override
- String answer1() {
- return "B";
- }
- @Override
- String answer2() {
- return "A";
- }
- @Override
- String answer3() {
- return "C";
- }
- }
只要继承试卷类, 重写下答案方法即可, 学生 B 也一样.
- package com.lwx.template_method;
- /**
- * Created with IntelliJ IDEA.
- * Description:
- * User: lwx
- * Date: 2019-03-11
- * Time: 22:49
- */
- public class StudentBPaper extends TestPaper {
- @Override
- String answer1() {
- return "C";
- }
- @Override
- String answer2() {
- return "B";
- }
- @Override
- String answer3() {
- return "A";
- }
- }
然后我们看下测试类和运行结果.
- package com.lwx.template_method;
- /**
- * Created with IntelliJ IDEA.
- * Description:
- * User: lwx
- * Date: 2019-03-11
- * Time: 22:00
- */
- public class Test {
- public static void main(String[] args) {
- TestPaper testPaper = null;
- System.out.println("学生 A 答题");
- testPaper = new StudentAPaper();
- testPaper.answerQuestion();
- System.out.println("----------------------------");
- System.out.println("学生 B 答题");
- testPaper = new StudentBPaper();
- testPaper.answerQuestion();
- }
- }
由于试卷是一样的, 所以完全可以抽象成父类, 然后在子类中去填写答案, 这样就是通过把不变的行为搬移到超类, 去除子类中的重复代码, 这也是模板方法的特点.
使用过 Servlet 的人都清楚, 需要继承一个叫 HttpServlet 的抽象类. HttpServlet 类提供了一个 service() 方法, 这个方法调用七个 do 方法中的一个或几个, 完成对客户端调用的响应. 这些 do 方法需要由 HttpServlet 的具体子类提供, 因此这是典型的模板方法模式. 下面是 service() 方法的源代码.
- protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- String method = req.getMethod();
- long lastModified;
- if (method.equals("GET")) {
- lastModified = this.getLastModified(req);
- if (lastModified == -1L) {
- this.doGet(req, resp);
- } else {
- long ifModifiedSince = req.getDateHeader("If-Modified-Since");
- if (ifModifiedSince < lastModified) {
- this.maybeSetLastModified(resp, lastModified);
- this.doGet(req, resp);
- } else {
- resp.setStatus(304);
- }
- }
- } else if (method.equals("HEAD")) {
- lastModified = this.getLastModified(req);
- this.maybeSetLastModified(resp, lastModified);
- this.doHead(req, resp);
- } else if (method.equals("POST")) {
- this.doPost(req, resp);
- } else if (method.equals("PUT")) {
- this.doPut(req, resp);
- } else if (method.equals("DELETE")) {
- this.doDelete(req, resp);
- } else if (method.equals("OPTIONS")) {
- this.doOptions(req, resp);
- } else if (method.equals("TRACE")) {
- this.doTrace(req, resp);
- } else {
- String errMsg = lStrings.getString("http.method_not_implemented");
- Object[] errArgs = new Object[]{method};
- errMsg = MessageFormat.format(errMsg, errArgs);
- resp.sendError(501, errMsg);
- }
- }
下面我们看下 HttpServlet 的结构图, 并写一个简单的 Servlet 例子.
- package com.lwx.template_method.servlet;
- import javax.servlet.ServletException;
- import javax.servlet.annotation.webServlet;
- import javax.servlet.http.HttpServlet;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- /**
- * Created with IntelliJ IDEA.
- * Description:
- * User: lwx
- * Date: 2019-03-11
- * Time: 22:05
- */
- @WebServlet(name = "myServlet", urlPatterns = "/myServlet")
- public class MyServlet extends HttpServlet {
- protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- }
- protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- response.getWriter().write("hello, world");
- }
- }
这里使用 @WebServlet 注解就不用在 Web.xml 配置了, 具体的内容可以看这篇博客 , 我们重写了 doGet 和 doPost, 由于是简单示例 doPost 我就不写了, 只在 doGet 返回 hello,world, 最后我们用 tomcat 启动工程.
模板方法的优点和缺点:
优点:
1. 模板方法提供了一个很好的代码复用平台.
2. 实现了反向控制, 通过一个父类调用其子类的操作, 通过对子类的具体实现扩展不同的行为, 实现了反向控制, 符合 "开闭原则".
缺点:
1. 每一个不同的实现都需要一个子类来实现, 导致类的个数增加, 使得系统更加庞大.
最后附上 demo 的 githup 地址: https://github.com/yijinqincai/design_patterns
来源: https://www.cnblogs.com/yijinqincai/p/10513843.html