1、了解模板方法

1.1 模式定义

定义一个操作算法中的框架,而将这些步骤延迟加载到子类中。

它的本质就是固定算法框架。

1.2 解决何种问题

让父类控制子类方法的调用顺序

模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

1.3 模式好处

开发人员在开发时,只需要考虑方法的实现。不需要考虑方法在何种情况下被调用。实现代码复用。

1.4 模式适合场景

  • 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。

  • 各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。

  • 需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

2、示例程序

例子说明:

小明来买房.业务员小二接待小明.小二带领小明去看房,小明觉得还不错.留下了联系方式,就离开了

小明来买房.业务经理小强接待小明.小二带领小明去看房,提出了一些建议和购房优惠,小明觉得优惠还不错.留下了联系方式并且交了押金,就离开了

经理还是挺会套路的,哈哈哈哈

2.1、抽象类,定义模板

定义一个AbstractDisplay抽象类

package cn.design.template;

/**
* @author lin
* @version 1.0
* @date 2020-07-15 17:09
* @Description 抽象类, 定义模板方法
*/
public abstract class AbstractDisplay {
   public abstract void join();    public abstract void execute();    public abstract void exit();    /**
    * 模板方法
    */
   public final void display() {
       join();
       execute();
       exit();
  } }

2.2、业务员小二

定义一个SalesmanDisplay继承AbstractDisplay

package cn.design.template;

/**
* @author lin
* @version 1.0
* @date 2020-07-15 17:14
* @Description 业务员 小二
*/
public class SalesmanDisplay extends AbstractDisplay {
   /**
    * 小明
    */
   String name;    public SalesmanDisplay(String name) {
       this.name = name;
  }    @Override
   public void join() {
       System.out.println("------- start -------");
       System.out.println("-- 我是" + this.name + " 来看看房--");
       System.out.println("-- 你好 ,我是 业务员小二 , 走 我带你来看房");
  }    @Override
   public void execute() {
       System.out.println("----------- look --------");
       System.out.println(" 这个房还是挺大的,而且还是新房,精装修的 ");
  }    @Override
   public void exit() {
       System.out.println("----------- exit ---------");
       System.out.println("今天看房效果还不错,双方留下了联系方式");
  }
}

2.3、经理小强

定义ManagerDisplay继承AbstractDisplay

package cn.design.template;

/**
* @author lin
* @version 1.0
* @date 2020-07-15 17:14
* @Description 经理 小强 的做法
*/
public class ManagerDisplay extends AbstractDisplay {
   /**
    * 小明
    */
   String name;    public ManagerDisplay(String name) {
       this.name = name;
  }    @Override
   public void join() {
       System.out.println("------- start -------");
       System.out.println("-- 我是" + this.name + " 来看看房--");
       System.out.println("-- 你好 ,我是 经理小强 ,我带你来看房 而且还有一些优惠政策");
  }    @Override
   public void execute() {
       System.out.println("----------- look --------");
       System.out.println(" 这个房区是属于学区房, 最近我们搞活动,你提前交一些定金,回头会有打98折的活动");
       System.out.println(" 我都会为你全权负责的, 这个你就放心好了,放心买 ");
  }    @Override
   public void exit() {
       System.out.println("----------- exit ---------");
       System.out.println("小明愚蠢的交了押金,双方留下了联系方式,后来小明不要买了,押金没了");
  }
}

2.4、Main测试类

package cn.design.template;

/**
* @author lin
* @version 1.0
* @date 2020-07-15 16:09
* @Description TODO
*/
public class Main {
   public static void main(String[] args) {
       AbstractDisplay a1 = new SalesmanDisplay("小明啊");
       a1.display();
       System.out.println();
       AbstractDisplay a2 = new ManagerDisplay("ming");
       a2.display();
  }
}

运行结果如下所示:

------- start -------
-- 我是小明啊 来看看房--
-- 你好 ,我是 业务员小二 , 走 我带你来看房
----------- look --------
这个房还是挺大的,而且还是新房,精装修的
-----------  exit  ---------
今天看房效果还不错,双方留下了联系方式 ------- start -------
-- 我是ming 来看看房--
-- 你好 ,我是 经理小强 ,我带你来看房 而且还有一些优惠政策
----------- look --------
这个房区是属于学区房, 最近我们搞活动,你提前交一些定金,回头会有打98折的活动
我都会为你全权负责的, 这个你就放心好了,放心买
-----------  exit  ---------
小明愚蠢的交了押金,双方留下了联系方式,后来小明不要买了,押金没了

3、模式结构

在Template Method模工中有以下登场用色。

◆ AbstractClass (抽象类)

AbstractClass角色不仅负责实现模板方法,还负责声明在模板方法中所使用到的抽象方法。这些抽象方法由子类ConcreteClass角色负责实现。在示例程序中,由AbstractDisplay类扮演此角色。

◆ ConcreteClass (具体类)

该角色负责具体实现AbstractClass角色中定义的抽象方法。这里实现的方法将会在AbstractClass角色的模板方法中被调用。在示例程序中,由CharDisplay类和stringDisplay类扮演此角色。

如下图:

4. 模式在Servlet中的应用

4.1 自己实现一下

浏览器向服务端发送一个请求,常用请求方式有两种,get请求和post请求,这两种请求方式会导致请求参数在请求协议包(Http包)中的位置是不一样的,那么请求协议包中不同的内容到达服务端之后会有不同的对象进行处理,如请求头的内容由tomcat负责,请求体中的内容由request负责,所以此时,开发人员在拿到service()方法后考虑到它可以接受所有请求方式,因此会针对不同的请求方式封装不同的请求方法。

建一个OneServlet 继承GenericServlet,实现service()方法,需要重写里面的doPost和doGet方法。

public class OneServlet extends GenericServlet {

   @Override
   public void service(ServletRequest req, ServletResponse arg1) throws ServletException, IOException {
       
       
               //1.从协议包【请求行】中来读取浏览器发送的请求方式
               HttpServletRequest request = (HttpServletRequest)req;//一般来说由父类修饰的对象由子类来修饰对象,目的就是功能扩充
               String method = request.getMethod();//POST GET
               if("GET".equals(method)){
                   doGet(req, arg1);
              }else if("POST".equals(method)){
                   doPost(req, arg1);
              }    
  }
   //处理浏览器发送的post请求
   public void doPost(ServletRequest arg0, ServletResponse arg1){
         //这里面是doPost封装好的方法
       
         System.out.println("doPost is run....");
  }
   
   //处理浏览器发送的get请求
   public void doGet(ServletRequest arg0, ServletResponse arg1){
         //这里面是doPost封装好的方法
       
         System.out.println("doGet is run....");
  }
   
}

现在开发人员面临的是,即需要做方法的实现,有需要考虑service()方法在何时调用。在实际开发过程中service()方法里面是一段重复性的代码,所有的servlet类实现中都需要写这么一段重复性的代码,这样重复的开发既增加工作量,又显得代码臃肿,降低了系统耦合度。模板方法设计模式就是来解决这个问题的。下面看一下怎么解决。

建立MyHttpServlet类(就是模板方法设计模式中的父类),继承GenericServlet类。

public  class MyHttpServlet extends GenericServlet {

   @Override
   public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
       //控制子类中的doGet和doPost方法
       //1.从协议包【请求行】来读取浏览器发送的请求方式
       HttpServletRequest request = (HttpServletRequest)req;
       String method = request.getMethod();//POST GET
       if("GET".equals(method)){
           doGet(req, res);//this.doGet()
      }else if("POST".equals(method)){
           doPost(req, res);
      }
  }
   
   public  void doPost(ServletRequest arg0, ServletResponse arg1){
       
  }
   
   public void doGet(ServletRequest arg0, ServletResponse arg1){
       
  }
   
}

建立TwoServlet类,此时此刻开发人员不用去考虑何时调用doGet方法。当调用TwoServlet类的时候,tomcat一定是调用它的service()方法。

/**
* Servlet implementation class TwoServlet
*/
public class TwoServlet extends MyHttpServlet {
   
   //选择是接受doGet方法还是doPost方法
   
   @Override
   public void doGet(ServletRequest arg0, ServletResponse arg1) {
         System.out.println("ThreeServlet doGet is run...");
  }
   
}

测试代码localhost:8080/.../...

ThreeServlet doGet is run...

5、Tomcat源码之HttpServlet

HttpServlet也是继承了GenericServlet ,跟踪找到Service()方法,发现有两个service()方法。

   //这个方法是从它的父类GenericServlet继承过来的
   @Override
   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);//调用的是自己声明的service方法,重载。
  }
}

进入到自己声明的service()方法

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

发现service方法没有使用final,这是因为如果使用final修饰,就彻底断绝了我们下游开发人员的开发,这样是降低了系统的灵活度。

设计模式是问题解决思想(办法),没有固定的命令搭配 。

如果我们自己可以有这样一些解决办法,那就是好的设计模式。

发哥讲

如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~

● 扫码关注公众号

3、Template Method 模板方法 行为型设计模式的更多相关文章

  1. 设计模式13:Template Method 模板方法模式(行为型模式)

    Template Method 模板方法模式(行为型模式) 变与不变 变化——是软件永恒的主题,如何管理变化带来的复杂性?设计模式的艺术性和复杂度就在于如何分析,并发现体系中的变化点和稳定点,并使用特 ...

  2. Template Method 模板方法

      简介 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的细节 抽象模板AbstractClass的方法分为两类: 基本 ...

  3. Template Method 模板方法 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  4. 设计模式 : Template method 模板方法模式 -- 行为型

      设计模式中,模板模式面向的是方法级别的流程.(不过好像世界上大部分问题,都可以抽象点.抽象点吧,最后抽象到一个方法里面吧.) 1. 一个方法,可以用来描述一个流程,这个流程涉及多个环节,不同环节可 ...

  5. 设计模式(22)--Template Method(模板方法模式)--行为型

    作者QQ:1095737364    QQ群:123300273     欢迎加入! 1.模式定义: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声 ...

  6. Template Method - 模板方法模式

    1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关.例子1: ...

  7. 设计模式C++学习笔记之九(Template Method模板方法模式)

      模板模式也是相当简单的一种模式,而且是比较常用的.模板模式是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些 ...

  8. 设计模式学习笔记——Template Method模板方法模式

    可能是最简单的设计模式. 而且你我都用过而不自知. 因为,模板方法模式也者,就是面向对象中的继承.公用部分放在父类,子类继承父类,然后扩展.呵呵.

  9. 模板方法(Template Method)---行为型

    1 基础知识 定义:定义了一个算法的骨架并允许子类为一个或多个步骤提供实现.特征:模板方法使得子类可以在不改变算法结构的前提下重新定义某些步骤. 使用场景: (1)需要固定定义算法骨架,实现一个算法的 ...

随机推荐

  1. POJ 1057 File Mapping 最详细的解题报告

    题目来源:POJ 1057 File Mapping 题目大意:像我的电脑那样显示文件夹和文件信息,其中在同一级目录内,文件夹排在文件的前面并且文件夹的顺序不变,同一级目录中文件按字母序排列.文件以‘ ...

  2. MySQL数据库修改表名

    修改表名 例:把表user 修改为tenant,SQL如下: rename table user to tenant:

  3. 5分钟带你快速入门和了解 OAM Kubernetes

    什么是 OAM? OAM 的全称为开放应用模型(Open Application Model),由阿里巴巴宣布联合微软共同推出. OAM 解决了什么问题? OAM 本质是为了解耦K8S中现存的形形色色 ...

  4. 第五章:理解RemoteViews

    RemoteView应该是一种远程View,表示的是一个View结构,他可以在其它进程中显示. 在android中使用场景有两种:通知栏和桌面小部件 5.1 RemoteView的应用 5.1.1 R ...

  5. SQL数据单条转多条(Lateral View)

    Lateral View和split,explode等UDTF一起使用,它能够将一行数据拆成多行数据,并在此基础上对拆分后的数据进行聚合. 单个Lateral View语句语法定义如下:lateral ...

  6. Mysql5.7前后修改用户密码变化

    本文主要强调修改密码的sql语句变化.如果是root密码忘记了,请参考Mysql忘记root密码怎么解决 Mysql 5.7以前修改密码 update mysql.user set password= ...

  7. .NET Core 微服务—API网关(Ocelot) 教程 [二]

    上篇文章(.NET Core 微服务—API网关(Ocelot) 教程 [一])介绍了Ocelot 的相关介绍. 接下来就一起来看如何使用,让它运行起来. 环境准备 为了验证Ocelot 网关效果,我 ...

  8. Pattern、Matcher的用法

    Pattern和Matcher Pattern 一个Pattern是一个正则表达式经编译后的表现模式. Matcher 一个Matcher对象是一个状态机器,它依据Pattern对象做为匹配模式对字符 ...

  9. Microsoft Cloud App Security 微软的云应用安全

    1.概述 微软2015年收购的一家云安全创业公司 Adallom 正式推出产品,同时更名为微软 Cloud App Security.Adallom 成立于 2012年,是一家 SaaS 云安全公司, ...

  10. c++ string类型举例(递归预习的边界)

    #include <iostream> #include <string> using namespace std; int main ( ) { string str; // ...