`
royzhou1985
  • 浏览: 254419 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

使用模板方法设计模式、策略模式 处理DAO中的增删改查

    博客分类:
  • Java
阅读更多
    摸板方法(Template Method)模式是一种非常简单而又经常使用的设计模式.先创建一个父类,把其中的一个或多个方法留给子类去实现,这实际上就是在使用摸板模式.所谓的摸板模式可以这样来理解:"在一个类中定义一个算法,但将此算法的某些细节留到子类中去实现.换句话说,基类是一个抽象类,那么你就是在使用一种简单形式的摸板模式."

    更近一步可以这样来理解:"准备一个抽象类,将部分逻辑以具体方法的形式实现,然后申明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方法实现这些抽象方法,从而对剩余的逻辑有不同的实现."

    将一个类的基本部分抽取出来放到一个基类中,这样它就不必重复出现在几个派生类里.

抽象摸板角色:(抽象父类)
1. 定义了一个或多个抽象操作,以便让子类实现.
2. 定义并实现了一个摸板方法.

具体摸板角色:(具体实现类)
1. 实现父类所定义的一个或多个抽象方法.
2. 每一个抽象摸板角色都可以有任意多个具体摸板角色与之对应.
3. 每一个具体摸板角色都可以给出这些抽象方法的不同实现.

模式中的方法种类

    1. 抽象模板角色里提供完整的方法,它完成了所有派生类都要用到的一些基本功能.

    2. 抽象模板角色里只提供空方法,把功能全部留给派生类去实现.

    3. 抽象模板角色里只包含某些操作的默认实现,派生类里可以重新定义这些方法的实现.

    4. 抽象模板角色里模板方法,他是一个调用抽象方法,钩子方法以及具体方法的各种组合.

在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中
abstractDao.java
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()) {
				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实现类中的代码就变得简单明了很多了
UserDaoImpl.java
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这个实现,而且不方便,程序不够灵活
	@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,用它来处理我们查询到的结果集

MyDaoTemplate.java
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 {
	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这个接口的类来处理我们的结果集(在这里我们使用的是匿名类)
UserDaoImpl1.java
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.造成很多的策略类(实现类)。


分享到:
评论
1 楼 itlangqun 2012-03-13  
相当好的一片文章,受教了,谢谢!!!

相关推荐

    Mybatis通用增删改查

    在实际开发中,为了提高代码的复用性和减少重复工作,开发者通常会实现一套通用的增删改查模板,这就是“Mybatis通用增删改查”的概念。 1. **基础 DaoImpl 概念** Dao(Data Access Object)接口是Java中用于...

    PHP增删改查模板(原生PHP+BootStrap前端框架)

    涵盖php增删改查的所有操作,并按照java的mvc设计模式写的(只是没写service,但dao层和controller,pojo,dbhelper还是有写的) 需要自己建立一个login表,有id(int auto_increment PK),user(varchar),pwd(varchar) 这三个...

    JSP网页连接数据库增删改查模板

    **JSP网页连接数据库增删改查模板** JSP(JavaServer Pages)是一种基于Java的动态网页技术,常用于构建企业级Web应用。本模板提供了一种基础框架,用于通过JSP实现对数据库中的数据进行增(Add)、删(Delete)、...

    基于SSH2的增删改查及分页完整项目

    这个"基于SSH2的增删改查及分页完整项目"提供了一个全面的示例,帮助开发者理解如何在实际应用中实现数据的增、删、改、查操作以及分页功能。 **Struts2** 是一个MVC(Model-View-Controller)框架,负责处理HTTP...

    Jfinal 实例(增删改查)

    **Jfinal 框架详解:增删改查操作实例** **一、Jfinal 框架介绍** Jfinal 是一款基于 Java 语言的轻量级 Web 开发框架,它以 MVC(Model-View-Controller)设计模式为核心,旨在简化 Java Web 开发,提高开发效率...

    springMVC 增删改查模板

    在本项目 "springMVC 增删改查模板" 中,我们将探讨如何使用 Spring MVC 来实现基本的数据操作功能,包括添加(Add)、删除(Delete)、修改(Update)和查询(Query)。这个项目非常适合初学者入门,帮助他们理解 ...

    dao.zip_sql增删改查

    在这个“dao.zip_sql增删改查”压缩包中,我们关注的是如何通过DAO类来实现对SQL Server 2005数据库的数据进行增删改查操作。以下是对这一主题的详细说明: 1. **DAO接口与实现**: - DAO接口通常定义了一系列方法...

    FristFreeMarker demo 增删改查

    【标题】"FristFreeMarker demo 增删改查" 涉及的主要知识点是使用FreeMarker模板引擎进行Java Web应用中的数据展示,结合SSH(Spring、Struts、Hibernate)框架实现CRUD操作。FreeMarker是一个开源的模板语言,用于...

    简单的SSHdemo 增删改查

    在Service层,我们可以定义EmployeeService接口和其实现类,接口中声明增删改查的方法,实现类中则使用Hibernate的Session对象来执行这些操作。例如,`saveEmployee(Employee employee)`用于保存新员工,`...

    Struts增删改查

    在"Struts增删改查"这个主题中,我们将深入探讨如何使用Struts框架来处理基本的数据操作,如添加(Add)、删除(Delete)、修改(Update)和查询(Query)。 1. **MVC模式**: MVC模式是一种将业务逻辑、数据和...

    ssh登录+课程增删改查功能的入门源代码

    5. **课程的增删改查界面**:这些界面由Struts的JSP(JavaServer Pages)或Freemarker模板创建,用户可以通过这些界面进行交互。每个操作对应一个Action,Action处理用户的请求并调用Service层进行业务处理。Service...

    java代码自动生成,模版式工程单表的增删改查接口控制器等

    Java代码自动生成是一种提高开发效率的方法,通过自动化工具,开发者可以快速生成常见的增删改查(CRUD)接口、控制器、服务层以及数据访问对象(DAO)等代码,避免重复劳动,专注于业务逻辑的设计。本工程就是这样...

    自定义框架实现用户增删改查

    这里我们关注的是如何使用自定义框架来实现用户管理中的基本操作:增删改查。这个主题通常涉及到Web开发,尤其是Java平台上的MVC(Model-View-Controller)架构,例如Struts框架。以下将详细介绍这一过程。 首先,...

    SSH增删改查2张表完整源码

    在这个源码中,你可能会看到Hibernate配置文件(hibernate.cfg.xml),实体类(Entity class),以及Session工厂和Session的使用,它们用于执行数据库的增删改查操作。 SSH_hotel文件名暗示这是一个关于酒店预订...

    java web 增删改查

    在Java Web开发中,"增删改查"(CRUD:Create, Read, Update, Delete)是最基础且关键的操作,广泛应用于各种业务场景,如用户管理、订单处理、商品库存等。以下是对这些核心概念的详细说明: 1. **创建(Create)*...

    SSH框架的增删改查

    在SSH框架中实现增删改查(CRUD)操作,通常需要以下步骤: 1. 创建实体类:对应数据库中的表,包含属性和getter/setter方法。 2. 配置Hibernate映射文件:定义实体类与数据库表的对应关系,包括主键、字段等。 3. ...

    maven整合ssm实现增删改查,

    这个压缩包文件“maven整合ssm实现增删改查”显然是一个已经配置好的项目模板,旨在帮助开发者快速搭建具备基础CRUD(创建、读取、更新、删除)功能的应用。下面我们将详细探讨SSM框架的集成以及MyBatis的代码反转...

    JDBC连接数据与增删改查操作_MVC基础上的客户管理系统

    ### JDBC连接数据与增删改查操作_MVC基础上的客户管理系统 #### 1. JDBC简介与连接数据库 Java Database Connectivity (JDBC) 是 Java 语言中用来规范客户端程序如何访问数据库的应用程序接口,提供了诸如查询和...

    工厂模式实现数据库的增删改查

    在这个场景中,我们将讨论如何使用Java的工厂模式来实现对MySQL数据库的增、删、改、查(CRUD)操作。 首先,让我们了解下工厂模式的基本概念。工厂模式是一种创建型设计模式,它提供了一个创建对象的接口,但允许...

    一个简单的ssh框架实现的增删改查

    在"一个简单的ssh框架实现的增删改查"项目中,你可能找到了以下关键部分: 1. 数据库表结构:这部分包含了项目的数据库设计,可能包括用户表、商品表等,每个表都有对应的字段和约束,这些信息会直接影响到...

Global site tag (gtag.js) - Google Analytics