3、Template Method 模板方法 行为型设计模式
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 模板方法 行为型设计模式的更多相关文章
- 设计模式13:Template Method 模板方法模式(行为型模式)
Template Method 模板方法模式(行为型模式) 变与不变 变化——是软件永恒的主题,如何管理变化带来的复杂性?设计模式的艺术性和复杂度就在于如何分析,并发现体系中的变化点和稳定点,并使用特 ...
- Template Method 模板方法
简介 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中. 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤的细节 抽象模板AbstractClass的方法分为两类: 基本 ...
- Template Method 模板方法 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- 设计模式 : Template method 模板方法模式 -- 行为型
设计模式中,模板模式面向的是方法级别的流程.(不过好像世界上大部分问题,都可以抽象点.抽象点吧,最后抽象到一个方法里面吧.) 1. 一个方法,可以用来描述一个流程,这个流程涉及多个环节,不同环节可 ...
- 设计模式(22)--Template Method(模板方法模式)--行为型
作者QQ:1095737364 QQ群:123300273 欢迎加入! 1.模式定义: 模板方法模式是类的行为模式.准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声 ...
- Template Method - 模板方法模式
1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关.例子1: ...
- 设计模式C++学习笔记之九(Template Method模板方法模式)
模板模式也是相当简单的一种模式,而且是比较常用的.模板模式是定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些 ...
- 设计模式学习笔记——Template Method模板方法模式
可能是最简单的设计模式. 而且你我都用过而不自知. 因为,模板方法模式也者,就是面向对象中的继承.公用部分放在父类,子类继承父类,然后扩展.呵呵.
- 模板方法(Template Method)---行为型
1 基础知识 定义:定义了一个算法的骨架并允许子类为一个或多个步骤提供实现.特征:模板方法使得子类可以在不改变算法结构的前提下重新定义某些步骤. 使用场景: (1)需要固定定义算法骨架,实现一个算法的 ...
随机推荐
- 爬虫01 /jupyter、爬虫概述、requests基本使用
爬虫02 /jupyter.爬虫概述.requests基本使用 目录 爬虫02 /jupyter.爬虫概述.requests基本使用 1. jupyter的基本使用 2. 爬虫概述 3. reques ...
- 【五学x红小豆xRS】两边三地大联动-句型
<第五共和国> Tohara LY Sara'm, Sabang Chua Setuk KS Kareh Moh Induree Junchi Chueh? 阁下!和这样的虫豸在一起,怎么 ...
- DQL:查询表中的记录
DQL:查询表中的记录 * select * from 表名; 1. 语法: select 字段列表 from 表名列表 where 条件列表 group by 分组字段 having 分组之后的条件 ...
- 没想到 Google 排名第一的编程语言,为什么会这么火?
没想到吧,Python 又拿第一了! 在 Google 公布的编程语言流行指数中,Python 依旧是全球范围内最受欢迎的技术语言! 01 为什么 Python 会这么火? 核心还是因为企业需要用 ...
- Python Ethical Hacking - Intercepting and Modifying Packets
INTERCEPTING & MODIFYING PACKETS Scapy can be used to: Create packets. Analyze packets. Send/rec ...
- 集训作业 洛谷P3913 车的攻击
这个题一开始被我想复杂了,但总体差不多. 脑子清醒后我直接看他占领了几条长,几条宽,比如一个长3宽3的地图. 被占领了一条宽,就可以看成一个长3宽2的地图.这个长3宽2的地图就是出去可以被攻击的点剩下 ...
- T133316 57级返校测试重测-T4-字符串的修改
大致题意: 有一个A字符串和一个B字符串, 操作将A或A的一个后缀修改为B, 求最少的操作数. 有三个操作为: 删除: 删除掉 A 中的某一个字符. 添加: 将某一个字符添加到 A 中任意位置. 替换 ...
- 一次HTTP请求服务的完整过程-请求处理过程
0.DNS域名解析:递归查询.迭代查询 递归查询:客户端向第一个服务器查询,给最终结果 迭代查询:第一个服务器向根查询 1 .建立连接:接收或拒绝连接请求:三次握手的过程 提高HTTP 连接性能: 并 ...
- 关于ES6的let和const
变量 var存在的问题 可以重复声明 无法限制修改 没有块级作用域 (在全局范围内有效) 存在变量提升 const/let 不可以重复声明 let a = 1; let a = 2; var b = ...
- Angular 的前世今生
目录 序言 AngularJS 简介 Angular 2.0 的动机 现如今的 Angular Angular 的核心概念 参考 序言 Angular 一般意义上是指 Angular v2 及以上版本 ...