一天一个设计模式——模板方法(Template Method)模式
一、模式说明
现实世界中的模板是用于将事物的结构规律予以固定化、标准化的成果,它体现了结构形式的标准化。例如镂空文字印刷的模板,通过某个模板印刷出来的文字字体大小都是一模一样,但是具体使用什么材质的颜料,什么颜色的颜料来印刷文字,取决于具体实际业务场景的需要。由此可见,模板制定了某些固定的条条框框,以及事物的处理标准流程,但是并没有说明如何去做,具体如何做,取决于使用模板的人。
在程序设计领域,模板是具有一系列抽象方法的接口类,单看接口类,我们只能知道这个模板有哪些抽象方法以及这些方法的调用顺序,但最终这些方法具体做什么操作,仅从模板类无法得知。继承模板的不同的子类,对这些抽象方法可以有不同的实现,当父类的模板方法被调用时,程序就可以有不同的行为实现。
像这样,在父类中定义处理流程的框架,在子类中实现具体处理的模式,称为模板方法模式。
在通常的面向对象程序设计中,我们习惯于站在子类的角度思考问题:例如子类继承了父类的哪些方法和属性,子类如何扩展父类实现新的功能,子类如何覆盖父类的方法来改变程序的行为。现在换一种角度,站在父类的角度思考子类:期待子类需要实现的抽象方法,要求子类必须实现的抽象方法。这也是Java面向对象程序设计中抽象类设计的特点:抽象类并不说明具体要执行的操作,但是抽象类可以提前决定继承它的子类中的方法名(抽象类中的方法名),并定义这些方法的处理流程,这种在抽象阶段决定处理流程非常重要:
- 使处理逻辑通用化,父类模板方法中已经写好了每个方法调用的时机,并处理这些方法的结果,实现业务算法,因此子类无需重复编写如何调用这些方法的算法。
- 在子类中实现父类的抽象方法时,需要充分理解这些抽象方法的调用时机,从而实现子类与父类之间的协作。
- 父类与子类的一致性,根据里氏替换原则(LSP),可以使用父类的变量保存子类的实例,且无论变量保存的是哪个子类实例,调用父类的模板方法,程序都可以正常工作。
举个具体的例子,在程序中访问数据库,无论是什么数据库(mysql、oracle、h2),要操作它们都要做一些特定步骤的操作:
- 1. 建立数据库连接
- 2. 创建Connection连接
- 3. 创建statement或者preparedStateement
- 4. 执行sql,返回ResultSet
- 5. 关闭resultSet
- 5.关闭statement
- 6.关闭Connection
Spring针对不同的平台,提供了几种不同的模板:
- 直接使用JDBC:提供了JdbcTemplate
- 使用ORM框架:HibernateTemplate和JpaTemplate
二、模板方法(Template Method)模式类图
三、模板方法(Template Method)模式中的角色
- AbstractClass抽象类:负责实现模板方法,并声明要用到的抽象方法。
- ConcreteClass具体类:负责实现AbstractClass抽象类中的抽象方法,这些方法会被AbstactClass抽象类中的模板方法调用。
四、代码示例
这里使用Spring的JDBCTemplate来演示模板方法模式:
1:创建java控制台应用程序,并添加spring相关依赖(或者使用maven创建java项目),项目目录结构如下:
注:adapterpattern包和iteratorpattern包是之前设计模式的代码示例包,无需理会(也可以查看我之前的博客,里面有说明这些代码是如何创建的)。
2:创建数据源的Bean,即上图中的ContextBeans类:
package com.designpattern.cn.templatemethodpattern; import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.stereotype.Component; import javax.sql.DataSource; @Component
public class ContextBeans {
@Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://10.211.55.100:3306/fruit_sale_system");
dataSource.setUsername("root");
dataSource.setPassword("123456");
return dataSource;
}
}
3:启用Spring容器的自动扫描配置类SpringConfig:
package com.designpattern.cn.templatemethodpattern; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan
public class SpringConfig {
}
4:测试使用模板方法操作数据库执行结果:
可以看到上述代码中,我只进行了Spring的基本配置,并为项目设置了一个mysql数据源,通过创建模板的实例JdbcTemplate,就可以直接调用queryForObject模板方法,实现业务查询。
五、相关的模式
- 工厂方法(FactoryMethod)模式:工厂方法模式是将模板方法用于生成实例的的典型例子。
- 策略(Strategy)模式:模板方法模式中,使用继承来改变程序的行为,而在策略模式中,使用委托改变程序的行为,并替换整个算法。
一天一个设计模式——模板方法(Template Method)模式的更多相关文章
- 行为型设计模式之模板方法(TEMPLATE METHOD)模式 ,策略(Strategy )模式
1 模板方法(TEMPLATE METHOD)模式: 模板方法模式把我们不知道具体实现的步聚封装成抽象方法,提供一些按正确顺序调用它们的具体方法(这些具体方法统称为模板方法),这样构成一个抽象基类.子 ...
- 设计模式之Template Method模式
作用:将具体的处理交给子类 什么是Template Method模式? Template Method模式是指带有模板功能的模式,组成模板的方法被定义在父类中,且这些方法为抽象方法.子类去实现父类中的 ...
- 封装算法: 模板方法(Template Method)模式
template method(模板方法)模式是一种行为型设计模式.它在一个方法中定义了算法的骨架(这种方法被称为template method.模板方法),并将算法的详细步骤放到子类中去实现.tem ...
- 设计模式:模板方法(Template method)
首先我们先来看两个例子:冲咖啡和泡茶.冲咖啡和泡茶的基本流程如下: 所以用代码来创建如下: 咖啡:Caffee.java public class Coffee { void prepareRecip ...
- C#设计模式——模板方法(Template Method)
一.概述在软件开发中,对某一项操作往往有固定的算法结构,而具体的子步骤会因为不同的需要而有所不同.如何可以在稳定算法结构的同时来灵活应对子步骤变化的需求呢?二.模板方法模板方法是一种常见的设计模式,它 ...
- 【设计模式】Template Method模式
OO基金会 封装 多态 继承 OO原则 封装变化 多用组合,少用继承 针对接口编程.不针对实现编程 为交互对象的松耦合设计而努力 类应该对扩展开放,对改动关闭 依赖抽象,不要依赖详细类 仅仅和朋友交谈 ...
- 设计模式:template method模式
思想:在父类中定义处理流程的框架,在子类中实现具体的处理方法 优点:在父类中定义处理的算法,无需在每个子类中重复编写 继承关系图: 例子: //接口定义 class Parent { public: ...
- 宋宝华:Linux设备驱动框架里的设计模式之——模板方法(Template Method)
本文系转载,著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 作者: 宋宝华 来源: 微信公众号linux阅码场(id: linuxdev) 前言 <设计模式>这本经典 ...
- Template Method模式和Strategy模式有何异同
Template Method模式和Strategy模式有何异同 博客分类: 设计模式 Java Template Method模式很容易理解,就是由基类提供一个模板,将各子类中不变的行为提取到基类 ...
随机推荐
- Centos7 静默安装 Oracle11G
1.准备安装包: 安装包官网下载地址:https://www.oracle.com/technetwork/database/enterprise-edition/downloads/112010-l ...
- liunx mysql 5.7 二进制安装
liunx 5.6版本 本人安装次数不下20次,基本上按照正常的操作流程不会出现什么问题,一切顺利. 今天开发新项目需要按照mysql 5.7 版本.mysql 5.7版本和mysql 5.6版本变化 ...
- id 和 class的区别
id 选择器 ID 只能被指定单个元素使用,无法多个元素使用.像你的身份证号,是唯一的,id 选择器以 “#” 来定义.id选择器的优先级高于class选择器的优先级的 # userid { text ...
- ionic实现滑动的三种方式
在移动端受屏幕大小所限,展示内容很多的时候,就要使部分区域进行滑动.本文展示项目中所有到的几种方式,大家可以看自己的需求选择合适的滑动方式.实现滑动的基本原理,有两个容器A.B,假如A在外层,B在内层 ...
- [转]SparkSQL – 有必要坐下来聊聊Join
转载自网易范欣欣http://hbasefly.com Join背景介绍 Join是数据库查询永远绕不开的话题,传统查询SQL技术总体可以分为简单操作(过滤操作-where.排序操作-limit等), ...
- leetcode1302 Deepest Leaves Sum
""" Given a binary tree, return the sum of values of its deepest leaves. Example 1: I ...
- ACM-生化武器
Description在一个封闭的房间里,gogo给大家表演了他的屁遁术,人果然一下没影了,但是他留下的“生化武器”,却以每秒1米的速度向上下左右扩散出去.为了知道自己会不会被“毒”到,你果断写了个算 ...
- STM32之GD25Q256应用笔记
前言 使用标准SPI指令格式: 3字节地址模式或4字节地址模式: 支持SPI 总线 模式0 和 模式3: 存储容量32MB: 时钟频率范围:80Mhz – 104Mhz: 主机:STM32F103ZE ...
- 如何更改RStudio(或R)中的默认目录
方法一: Session -> Set Working Directory -> Choose Directory ... or shortcut (Ctrl+Shift+H) 方法二 s ...
- TensorFlow--交互式使用--tf.InteractiveSession()
用tf.Session()创建会话时只有在会话中run某个张量才能得到这个张量的运算结果,而交互式环境下如命令行.IPython,想要执行一行就得到结果,这就需要用到tf.InteractiveSes ...