【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查
分析
在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大.
因此,我们可以将dao中增删改查分开为两个部分,
一些是不变的代码,比如创建局部变量Connection conn,PreparedStatement ps,ResultSet rs等等。
public int update(String sql, Object[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DbUtils.getConnection();
ps = conn.prepareStatement(sql);
//参数设置
return ps.executeUpdate();
} catch (SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
DbUtils.close(rs);
DbUtils.close(ps);
DbUtils.close(conn);
}
}
上面代码,在每个操作中基本一样,我们可以将其提取出来。
另外一部分是变化的代码,即我们传入的参数如sql,以及参数列表Object[] params等等。
对vo的增删改查可以使用下面方法:
public int update(String sql, Object[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DbUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++)
ps.setObject(i + 1, args[i]);
return ps.executeUpdate();
} catch (SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
DbUtils.close(rs);
DbUtils.close(ps);
DbUtils.close(conn);
}
}
使用模板模式整改
对vo的查询关系到对ResultSet的处理,我们可以在抽象父类中定义一个抽象的方法。
abstract Object rowMapper(ResultSet rs) throws SQLException;
这样子类继承了抽象父类后必须实现rowMapper这个方法。这样我们就可以构造出一个将方法抽象到一个父类AbstractDao中。
package com.royzhou.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.royzhou.db.DbUtils;
import com.royzhou.exception.DaoException;
public abstract class AbstractDao {
public Object find(String sql, Object[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DbUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++)
ps.setObject(i + 1, args[i]);
rs = ps.executeQuery();
Object obj = null;
if (rs.next()) {
//rowMapper实现在子类中,根据子类算法进行处理
//只能有一种算法处理,如果要想对rs有不同处理要使用下面的策略模式
obj = rowMapper(rs);
}
return obj;
} catch (SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
DbUtils.close(rs);
DbUtils.close(ps);
DbUtils.close(conn);
}
}
abstract protected Object rowMapper(ResultSet rs) throws SQLException;
public int update(String sql, Object[] args) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DbUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++)
ps.setObject(i + 1, args[i]);
return ps.executeUpdate();
} catch (SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
DbUtils.close(rs);
DbUtils.close(ps);
DbUtils.close(conn);
}
}
}
然后在UserDaoImpl中我们继承AbstractDao这个类并实现rowMapper这个抽象方法(子类实现父类定义的抽象方法)。
@Override
protected Object rowMapper(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getString("id"));
user.setUserName(rs.getString("userName"));
user.setLoginId(rs.getString("loginId"));
user.setPassword(rs.getString("password"));
return user;
}
这样dao实现类中的代码就变得简单明了很多了。完整dao实现类UserDaoImpl代码如下:
package com.royzhou.dao.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.royzhou.dao.AbstractDao;
import com.royzhou.vo.User;
public class UserDaoImpl extends AbstractDao {
public User findUser(String id) {
String sql = "select id, userName, loginId, password from user where id=?";
Object[] args = new Object[] { id };
Object user = super.find(sql, args);
return (User) user;
}
@Override
protected Object rowMapper(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getString("id"));
user.setUserName(rs.getString("userName"));
user.setLoginId(rs.getString("loginId"));
user.setPassword(rs.getString("password"));
return user;
}
public void delete(User user) {
String sql = "delete from user where id=?";
Object[] args = new Object[] { user.getId() };
super.update(sql, args);
}
public void update(User user) {
String sql = "update user set userName=?, loginId=?, password=? where id=? ";
Object[] args = new Object[] { user.getUserName(), user.getLoginId(),
user.getPassword(), user.getId() };
super.update(sql, args);
}
}
使用策略模式整改
不过上面代码查询的时候存在一个问题:假如我只需要查找username这一列的数据,我们必须重写rowMapper这个实现,而且不方便,程序不够灵活。rowMapper实现如下:
@Override
protected Object rowMapper(ResultSet rs) throws SQLException {
return rs.getString("userName");
}
这显然不是我们想要看到的。为了解决这个问题,我们可以使用策略模式来改进我们的程序。
GOF《设计模式》一书对Strategy模式是这样描述的:
定义一系列的算法,把他们一个个封装起来,并且使它们可相互替换。Strategy模式使算法可独立于使用它的客户而变化。
Strategy模式以下列几条原则为基础:
1) 每个对象都是一个具有职责的个体。
2) 这些职责不同的具体实现是通过多态的使用来完成的。
3) 概念上相同的算法具有多个不同的实现,需要进行管理。
如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态的让一个对象在许多行为中选择一种行为。
如果系统需要动态地在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,由于多态性原则。客户端可以选择使用任何一个具体算法类,并只持有一个数据类型是抽象算法类的对象。
设计原则是把一个类中经常改变或者将来可能改变的部分提取出来,作为一个接口,然后在类中包含这个对象的实例,这样类的实例在运行时就可以随意调用实现了这个接口的类的行为。
通常,策略模式适用于当一个应用程序需要实现一种特定的服务或者功能,而且该程序有多种实现方式时使用。
在处理ResultSet结果集的时候,我们可以使用接口变成,将结果集的操作交给一个接口来处理
public Object find(String sql, Object[] args, RowMapper rowMapper)
其中RowMapper这个接口里面只有一个方法。
public Object mapRow(ResultSet rs) throws SQLException
用它来处理我们查询到的结果集。
package com.royzhou.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.royzhou.db.DbUtils;
import com.royzhou.exception.DaoException;
public class MyDaoTemplate {
//根据传入的策略RowMapper来处理结果集ResultSet
public Object find(String sql, Object[] args, RowMapper rowMapper) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DbUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < args.length; i++)
ps.setObject(i + 1, args[i]);
rs = ps.executeQuery();
Object obj = null;
if (rs.next()) {
obj = rowMapper.mapRow(rs);
}
return obj;
} catch (SQLException e) {
throw new DaoException(e.getMessage(), e);
} finally {
DbUtils.close(rs);
DbUtils.close(ps);
DbUtils.close(conn);
}
}
}
这样我们就可以根据不同的需要使用实现了RowMapper这个接口的类来处理我们的结果集(在这里我们使用的是匿名类) 。
package com.royzhou.dao.impl;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.royzhou.dao.MyDaoTemplate;
import com.royzhou.dao.RowMapper;
import com.royzhou.vo.User;
public class UserDaoImpl1 {
private MyDaoTemplate template = new MyDaoTemplate();
public User findUser(String id) {
String sql = "select id, userName, loginId, password from user where id=?";
Object[] args = new Object[] { id };
Object user = this.template.find(sql, args, new RowMapper(){
public Object mapRow(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getString("id"));
user.setUserName(rs.getString("userName"));
user.setLoginId(rs.getString("loginId"));
user.setPassword(rs.getString("password"));
return user;
}
});
return (User) user;
}
public String findUserName(String id) {
String sql = "select userName from user where id=?";
Object[] args = new Object[] {id};
Object userName = this.template.find(sql, args, new RowMapper(){
public Object mapRow(ResultSet rs) throws SQLException {
return rs.getString("userName");
}
});
return (String)userName;
}
}
经过这样的修改程序变得更加灵活了。对于不同的查询我们只需要用相对的策略写一个匿名类就可以了。
通过上面例子我们可以总结一下策略模式的优缺点:
优点:
1.可以很方便的动态改变算法或行为
2.避免使用多重条件转移语句
缺点:
1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
2.造成很多的策略类(实现类)。
【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查的更多相关文章
- 使用MVC5+Entity Framework6的Code First模式创建数据库并实现增删改查功能
此处采用VS2017+SqlServer数据库 一.创建项目并引用dll: 1.创建一个MVC项目 2.采用Nuget安装EF6.1.3 二.创建Model 在models文件夹中,建立相应的mode ...
- Entity Framework应用:使用EF的DataBase First模式实现数据库的增删改查
在上一篇文章中讲解了如何生成EF的DBFirst模式,接下来讲解如何使用DBFirst模式实现数据库数据的增删改查 一.新增数据 新增一个Student,代码如下: static void Add() ...
- Java设计模式(十二) 策略模式
原创文章,同步发自作者个人博客,http://www.jasongj.com/design_pattern/strategy/ 策略模式介绍 策略模式定义 策略模式(Strategy Pattern) ...
- 设计模式之第8章-策略模式(Java实现)
设计模式之第8章-策略模式(Java实现) “年前大酬宾了啊,现在理发冲500送300,冲1000送500了.鱼哥赶紧充钱啊,理发这事基本一个月一回,挺实惠的啊.不过话说那个理发店的老板好傻啊,冲10 ...
- MySQL数据库学习笔记(十一)----DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)
DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类) 一.DAO模式简介 DAO即Data Access Object,数据访问接口.数据访问:故名思义就是与数据库打交道.夹在业务逻辑与数据 ...
- MVC设计模式((javaWEB)在数据库连接池下,实现对数据库中的数据增删改查操作)
设计功能的实现: ----没有业务层,直接由Servlet调用DAO,所以也没有事务操作,所以从DAO中直接获取connection对象 ----采用MVC设计模式 ----采用到的技术 .MVC设计 ...
- 使用反射+策略模式代替项目中大量的switch case判断
我这里的业务场景是根据消息类型将离线消息存入mongoDB不同的collection中.其中就涉及到大量的分支判断,为了增强代码的可读性和可维护性,对之前的代码进行了重构. 先对比一下使用反射+策略模 ...
- 05_Elasticsearch 单模式下API的增删改查操作
05_Elasticsearch 单模式下API的增删改查操作 安装marvel 插件: zjtest7-redis:/usr/local/elasticsearch-2.3.4# bin/plugi ...
随机推荐
- Python IO编程
IO在计算机中指Input/Output,也就是输入和输出 一.文件读写 1.读文件 >>> f = open('/Users/michael/test.txt', 'r') --- ...
- (详细)华为荣耀V10 BKL-AL00的USB调试模式在哪里打开的步骤
每当我们使用pc连接安卓手机的时候,如果手机没有开启Usb开发者调试模式,pc则无法成功检测到我们的手机,有时我们使用的一些功能比较强的的app比如以前我们使用的一个app引号精灵,老版本就需要开启U ...
- ASP.NET Core 入门教程 6、ASP.NET Core MVC 视图布局入门
一.前言 1.本教程主要内容 ASP.NET Core MVC (Razor)视图母版页教程 ASP.NET Core MVC (Razor)带有Section的视图母版页教程 ASP.NET Cor ...
- 从分治算法到 Hadoop MapReduce
从分治算法说起 要说 Hadoop MapReduce 就不得不说分治算法,而分治算法其实说白了,就是四个字 分而治之 .其实就是将一个复杂的问题分解成多组相同或类似的子问题,对这些子问题再分,然后再 ...
- mssql 存储过程调用另一个存储过程中的结果的方法分享
转自:http://www.maomao365.com/?p=6801 摘要: 下文将分享"一个存储过程"中如何调用"另一个存储过程的返回结果",并应用到自身的 ...
- hive笔记:复杂数据类型-map结构
map 结构 1. 语法:map(k1,v1,k2,v2,…) 操作类型:map ,map类型的数据可以通过'列名['key']的方式访问 案例: select deductions['Feder ...
- 启动期间的内存管理之初始化过程概述----Linux内存管理(九)
在内存管理的上下文中, 初始化(initialization)可以有多种含义. 在许多CPU上, 必须显式设置适用于Linux内核的内存模型. 例如在x86_32上需要切换到保护模式, 然后内核才能检 ...
- Flex Builder 4.6切换语言
一.修改Flex builder 1.用无格式编辑器打开FlashBuilder.ini 2.把zh_CN替换成"en_US" 二.修改MyEclipse插件 1.用无格式编辑器打 ...
- A Deep Learning-Based System for Vulnerability Detection
本篇文献作者提出了一种基于深度学习来检测软件漏洞的方案. 摘要:作者开始基于深度学习的漏洞检测研究,是为了减轻专家手工定义特性的繁琐任务,需要制定一些指导性原则来适用于深度学习去进行漏洞探 ...
- LeetCode算法题-Detect Capital(Java实现)
这是悦乐书的第251次更新,第264篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第118题(顺位题号是520).给定一个单词,你需要判断其中大写字母的使用是否正确.当下 ...