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)需要固定定义算法骨架,实现一个算法的 ...
随机推荐
- ES6面试
未完持续 概念 ECMAScript6(以下简称ES6)是 JavaScript 语言的下一代标准,前者是后者的规格,后者是前者的一种实现. ES6(新增的)一些特性 1.变.常量:let声明变量,c ...
- 前端 /deep/ 深入样式(很深入的那种哦) 简单收藏
简单介绍:使用vue脚手架和elemen-ui开发的前端项目 遇到这样的场景: 对div下的el-select下拉组件 设置样式,直接在标签上用style属性是完全可以的,但我们的开发规范是前端样式 ...
- Redis(一)简介及安装、测试
一.Redis简介: 关于关系型数据库和nosql数据库 关系型数据库是基于关系表的数据库,最终会将数据持久化到磁盘上,而nosql数据 库是基于特殊的结构,并将数据存储到内存的数据库.从性能上而言, ...
- C语言学习笔记一---C语言概述
一.编程语言与解释语言 1.程序的执行 a.解释:借助一个能试图理解程序的程序,使计算机按要求执行你自己写的程序 b.编译:将所写程序翻译为机器语言写的程序,使计算机按要求执行你自己写的程序 2.两者 ...
- 来自马铁大神的Spark10年回忆录
本篇分享来自Martei在Spark AI Submit 2020的开场分享. 马铁是谁 什么!你不知道马铁是谁?Martei Zaharia(说实话,不知道谁给起的中文名字叫马铁,跟着叫就是了),现 ...
- SpringSecurity匹配规则介绍
SpringSecurity匹配规则一 URL匹配 requestMatchers() 配置一个request Mather数组,参数为RequestMatcher 对象,其match 规则自定义,需 ...
- Kafka 入门(三)--为什么 Kafka 依赖 ZooKeeper?
一.ZooKeeper 简介 1.基本介绍 ZooKeeper 的官网是:https://zookeeper.apache.org/.在官网上是这么介绍 ZooKeeper 的:ZooKeeper 是 ...
- 环境篇:DolphinScheduler-1.3.1安装部署及使用技巧
环境篇:DolphinScheduler-1.3.1安装部署 1 配置jdk JDK百度网盘:https://pan.baidu.com/s/1og3mfefJrwl1QGZGZDZ8Sw 提取码:t ...
- Alink漫谈(十五) :多层感知机 之 迭代优化
Alink漫谈(十五) :多层感知机 之 迭代优化 目录 Alink漫谈(十五) :多层感知机 之 迭代优化 0x00 摘要 0x01 前文回顾 1.1 基本概念 1.2 误差反向传播算法 1.3 总 ...
- pandas属性和方法
Series对象的常用属性和方法 loc[ ]和iloc[ ]格式示例表 Pandas提供的数据整理方法 Pandas分组对象的属性和方法 date_range函数的常用freq参数表