引入:这几天在看一本讲spring源码的书《SPRING技术内幕》里面在讲加载配置文件的时候,可以有不同的加载方式,如根据文件系统目录加载配置文件(FileSystemXmlApplicationContext),类路径加载配置文件(ClassPathXmlApplicationContext),以及根据项目上下文目录(XmlWebApplicationContext)加载配置文件。这个在加载的过程中就使用了模板设计模式,所以就来学习下模板设计模式。

1. 模板设计模式在书中定义:

  定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。

  通俗点的理解就是 :完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。

2. 如下网上找到的一个模板模式的类图:

  抽象父类(AbstractClass):实现了模板方法,定义了算法的骨架。

  具体类(ConcreteClass):实现抽象类中的抽象方法,即不同的对象的具体实现细节。

3. 实例说明

  来举个例子: 比如我们做菜可以分为三个步骤 (1)备料 (2)具体做菜 (3)盛菜端给客人享用,这三部就是算法的骨架 ;然而做不同菜需要的料,做的方法,以及如何盛装给客人享用都是不同的这个就是不同的实现细节。

下来我们就代码实现如下

 a. 先来写一个抽象的做菜父类:

public abstract class DodishTemplate {
/**
* 具体的整个过程
*/
protected void dodish(){
this.preparation();
this.doing();
this.carriedDishes();
}
/**
* 备料
*/
public abstract void preparation();
/**
* 做菜
*/
public abstract void doing();
/**
* 上菜
*/
public abstract void carriedDishes ();
}

 b. 下来做两个番茄炒蛋(EggsWithTomato)和红烧肉(Bouilli)实现父类中的抽象方法

/**
* 西红柿炒蛋
* @author aries
*/
public class EggsWithTomato extends DodishTemplate{ @Override
public void preparation() {
System.out.println("洗并切西红柿,打鸡蛋。");
} @Override
public void doing() {
System.out.println("鸡蛋倒入锅里,然后倒入西红柿一起炒。");
} @Override
public void carriedDishes() {
System.out.println("将炒好的西红寺鸡蛋装入碟子里,端给客人吃。");
} }
/**
* 红烧肉
* @author aries
*
*/
public class Bouilli extends DodishTemplate{ @Override
public void preparation() {
System.out.println("切猪肉和土豆。");
} @Override
public void doing() {
System.out.println("将切好的猪肉倒入锅中炒一会然后倒入土豆连炒带炖。");
} @Override
public void carriedDishes() {
System.out.println("将做好的红烧肉盛进碗里端给客人吃。");
} }

c. 在测试类中我们来做菜:

public class App {
public static void main(String[] args) {
DodishTemplate eggsWithTomato = new EggsWithTomato();
eggsWithTomato.dodish(); System.out.println("-----------------------------"); DodishTemplate bouilli = new Bouilli();
bouilli.dodish();
}
}

这样我们就实现了使用模板模式的一个完整的实例。

4. 在书本上看到过这么一个例子:

 去银行办业务,如取钱,存钱或者办卡等,基本都需要三个大的步骤(骨架),首先 (1)取号 (2)办具体业务 (3)服务评价打分,然后这三个步骤就可以抽取到父类中进行定义,(1)取号 (3)服务打分是相同操作,可以直接在父类总实现,然后(2)办具体的业务各不相同需要在子类中实现。如下我画个类图:

takeNumber(取号),trabsact(具体业务),evaluate(评价),process(骨架方法)。

5. 模板设计模式常在数据库操作中使用,我现在使用模板模式做一个JDBC的查询模板:

(1) 抽象查询父类

public abstract class AbstractDao {

    /**
* 查询
* @param sql
* @param params
* @return
*/
protected Object find(String sql, Object[] params) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Object obj = null;
try {
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
rs = ps.executeQuery();
while (rs.next()) {
obj = rowMapper(rs);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.free(rs, ps, conn);
}
return obj;
}

protected abstract Object rowMapper(ResultSet rs) throws SQLException; //同时可以添加 insert ,update 等方法
}

(2)具体的UserDao

/**
* userDao
*
* @author aries
*
*/
public class UserDao extends AbstractDao { public User findUser(int userId) {
String sql = "select * from t_user where userId = ?";
Object[] params = new Object[] { userId };
Object user = super.find(sql, params);
System.out.println((User) user);
return (User) user;
} @Override
protected Object rowMapper(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getInt("userId"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
user.setSex(rs.getString("sex"));
user.setAddress(rs.getString("address"));
return user;
}
}

(3)以上代码中用到的User类和JDBCUtil

public class JDBCUtils {
private static String url = "jdbc:mysql://localhost:3306/jdbcstudy";
private static String user = "root";
private static String password = "123"; private JDBCUtils() {
} static {
try {
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError(e);
}
} public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, user, password);
} public static void free(ResultSet rs, PreparedStatement ps, Connection conn){
if(rs != null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps != null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**
* 用户类
*
* @author aries
*
*/
public class User {
private Integer id;
private String name;
private Integer age;
private String sex;
private String address; //set...get省略
}

如上就使用模板模式做的查询,父类中做了算法骨架,子类中具体实现算法中的不同部分。

6. 模板模式的优点

 (1)具体细节步骤实现定义在子类中,子类定义详细处理算法是不会改变算法整体结构。

 (2)代码复用的基本技术,在数据库设计中尤为重要。

 (3)存在一种反向的控制结构,通过一个父类调用其子类的操作,通过子类对父类进行扩展增加新的行为,符合“开闭原则”。

7. 不足

每个不同的实现都需要定义一个子类,会导致类的个数增加,系统更加庞大。

原文引用自:https://www.cnblogs.com/qq-361807535/p/6854191.html

spring常用模式--模板模式的更多相关文章

  1. java模式:模板模式的简单理解

    1.模板模式就是用虚类作为基类将几个要执行差不多操作中相同的部分提取出来,不同的部分各自实现! 2.下面给出简单栗子: 我要进行的操作是将大象和狐狸放入冰箱,放入大象和狐狸有相同的步骤:开冰箱和关冰箱 ...

  2. Java设计模式(七)策略模式 模板模式

    (十三)策略模式 策略图案限定了多个封装算法,该算法可以相互替换包.法的客户.借用还有一位大神的样例. interface ICalculator{ public int calculate(Stri ...

  3. Spring中的设计模式:模板模式

    导读 模板模式在是Spring底层被广泛的应用,比如事务管理器的实现,JDBC模板的实现. 文章首发于作者的微信公众号[码猿技术专栏] 今天就来谈谈「什么是模板模式」.「模板模式的优缺点」.「模板模式 ...

  4. Spring中常见的设计模式——模板模式

    一.模板模式的应用场景 模板模式又叫模板方法模式(Template Method Pattern),指定义一个算法的骨架,并允许自雷为一个或者多个步骤提供实现.模板模式使得子类可以在不改变算法结果的情 ...

  5. 应聘阿里,字节跳动,美团必须掌握的Spring IOC与工厂模式

    Spring IOC与工厂模式 PS:本文内容较为硬核,需要对java的面向对象.反射.类加载器.泛型.properties.XML等基础知识有较深理解. (一)简单介绍 在讲Spring IOC之前 ...

  6. 模板模式(Template)

    行为型:Template(模板模式) 作为一个曾经爱好写文章,但是不太懂得写文章的人,我必须承认,开头是个比较难的起步. 模板模式常规定义:模板模式定义了一个算法步骤,把实现延迟到子类. 事实上模板模 ...

  7. 设计模式之 - 模板模式(Template Pattern)

    引入:这几天在看一本讲spring源码的书<SPRING技术内幕>里面在讲加载配置文件的时候,可以有不同的加载方式,如根据文件系统目录加载配置文件(FileSystemXmlApplica ...

  8. 设计模式——模板模式(C++实现)

    模板模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤.   模板模式通过把不变的行为搬移到超类,去除子类中的重复代码来 ...

  9. java设计模式之模板模式以及钩子方法使用

    1.使用背景 模板方法模式是通过把不变行为搬到超类,去除子类里面的重复代码提现它的优势,它提供了一个很好的代码复用平台.当不可变和可变的方法在子类中混合在一起的时候, 不变的方法就会在子类中多次出现, ...

随机推荐

  1. rsync 应用总结

    rysnc server端 1.vim /etcrsyncd.conf (用户rsync,目录,模块,非系统虚拟用户及密码文件) 2.创建共享目录 /data/www/{www,bbs,blog} 3 ...

  2. Nginx入门(一)——安装和配置

    1.下载地址 http://nginx.org/en/download.html 2.启动Nginx 进入window的cmd窗口,输入如下图所示的命令,进入到nginx目录(F:/nginx-1.8 ...

  3. vue-cli3 clone项目后如何安装插件及依赖模块启动项目

    一. 前提条件1.确保使用的是Node 8.11.0+和NPM 3+:2.确保已全局安装vue-clie3:npm install -g @vue/cli: 二.安装依赖 1.在安装依赖之前,先安装官 ...

  4. linux实操_shell预定义变量

    当前进程号: 运行后 后台最后一个进程号: 运行后

  5. proc文件系统详解

    /proc 文件系统是一个虚拟文件系统,通过它可以使用一种新的方法在 Linux内核空间和用户间之间进行通信.在 /proc 文件系统中,我们可以将对虚拟文件的读写作为与内核中实体进行通信的一种手段, ...

  6. 如何实现UI自动化?DevExpress Winforms帮你忙

    DevExpress Winforms Controls 内置140多个UI控件和库,完美构建流畅.美观且易于使用的应用程序.无论是Office风格的界面,还是分析处理大批量的业务数据,DevExpr ...

  7. Jquery select 三级联动 (需要JSON数据)

    Scripts/Category.js //Jquery三级类别联动 $(function () { BindCategory(); }) function BindCategory() { var ...

  8. HTTP权威指南与图解HTTP读书笔记

    目录 第1章 HTTP概述 1.1 Web客户端和服务器 1.2 资源 1.2.1 URI 1.2.2 URL 1.2.3 URN 1.3 事务 1.3.1 方法 1.3.2 状态码 1.3.3 We ...

  9. Girls and Boys POJ - 1466 【(二分图最大独立集)】

    Problem DescriptionIn the second year of the university somebody started a study on the romantic rel ...

  10. electron 打包成桌面运用

    最近在学习nodejs,得知Electron是通过将Chromium和Node.js合并到同一个运行时环境中,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一门技术.对于之前一直从 ...