DAO设计模式

DAO(Database Access Object,数据访问对象)的主要功能是数据操作,在程序的标准开发架构中属于数据层的操作。在整个DAO中实际上是以接口为操作标准,即客户端依靠DAO实现的接口进行操作,而服务端要将接口进行具体的实现。DAO由以下几个部分组成:

DatabaseConnection:专门负责数据库的打开与关闭操作的类。

VO:主要由属性、setter、getter方法组成,VO类中的属性与表中的字段相对应,每一个VO类的对象都表示数据库中的一条记录。

DAO:主要定义操作的接口,定义一系列数据库的原子性操作标准,如增加、修改、删除、按ID查询等。

Impl:DAO接口的真实实现类,完成具体的数据库操作,但是不负责数据库的打开和关闭。

Proxy:代理实现类,主要完成数据库的打开和关闭,并且调用真实实现类对象的操作。

Factory:工厂类,通过工厂类取得一个DAO的实例化对象。


下面以一个DAO代码来说明DAO设计模式:

假设数据库中有一个emp表,表中的字段如下:

empno INT(4) PRIMARY KEY

ename VARCHAR2(10)

job VARCHAR2(9)

hiredate DATE

sal FLOAT(7,2)


一.创建VO类——Emp.java:

该类是由属性、setter、getter方法组成,属性与数据库中的字段相对应。

package com.fcy.vo;

import java.util.Date;

public class Emp {
	
	private int empno;
	private String ename;
	private String job;
	private Date hiredate;
	private float sal;
	public int getEmpno() {
		return empno;
	}
	public void setEmpno(int empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
	public String getJob() {
		return job;
	}
	public void setJob(String job) {
		this.job = job;
	}
	public Date getHiredate() {
		return hiredate;
	}
	public void setHiredate(Date hiredate) {
		this.hiredate = hiredate;
	}
	public float getSal() {
		return sal;
	}
	public void setSal(float sal) {
		this.sal = sal;
	}
	
	
	
}

二.数据库的连接类——DatabaseConnection.java

该类是用来获得数据库的连接和关闭数据库。在任何需要数据库打开或关闭的地方,调用此类即可。

package com.fcy.dbc;

import java.sql.Connection;
import java.sql.DriverManager;

public class DatabaseConnection {

	private static final String DBDRIVER="oracle.jdbc.driver.OracleDriver";
	private static final String DBURL="jdbc:oracle:thin:@localhost:1521:orcl";
	private static final String DBUSER="system";
	private static final String DBPASSWORD="admin";
	private Connection conn=null;
	
	public DatabaseConnection() throws Exception{
		try{
			Class.forName(DBDRIVER);
			this.conn=DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD);
		}catch(Exception e){
			throw e;
		}
	}
	
	public Connection getConnection(){
		return this.conn;
	}
	
	public void close() throws Exception{
		if(this.conn!=null){
			try{
				this.conn.close();
			}catch(Exception e){
				throw e;
			}
		}
	}
}



三.定义DAO操作标准_IEmpDAO.java

该类是定义操作的接口。此类中定义了三个操作,当然也可以定义更多的操作。

package com.fcy.dao;

import java.util.List;

import com.fcy.vo.Emp;

public interface IEmpDAO {
	
	/**
	 * 数据库的增加操作,一般以doXxx的方式命名
	 * @param emp	要增加的数据对象
	 * @return		是否增加成功的标记
	 * @throws Exception  有异常交给被调用处处理
	 */
	public boolean doCreate(Emp emp)throws Exception;
	
	/**
	 * 查询全部数据,一般以findXxx的方式命名
	 * @param keyWord	查询关键字
	 * @return			返回全部查询结果,每个Emp对象表示表的一条记录
	 * @throws Exception 有异常交给被调用处处理
	 */
	public List<Emp> findAll(String keyWord) throws Exception;
	
	/**
	 * 根据雇员编号查询雇员信息
	 * @param empno 		雇员编号
	 * @return				雇员的VO对象
	 * @throws Exception	有异常交给被调用处处理
	 */
	public Emp findById(int empno) throws Exception;
	
}

四.真实主题实现类——EmpDAOImpl.java

该类实现了IEmpDAO接口,重写了IEmp DAO接口中的方法。但此类中,并未获取数据库的连接,因此此类中的方法不能用来直接操作数据库。

package com.fcy.dao.impl;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import com.fcy.dao.IEmpDAO;
import com.fcy.vo.Emp;

public class EmpDAOImpl implements IEmpDAO{
	
	private Connection conn=null;   //注意:数据库的连接未获取
	private PreparedStatement pstmt=null;
	public EmpDAOImpl(Connection conn){
		this.conn=conn;
	}

	@Override
	public boolean doCreate(Emp emp) throws Exception {
		boolean flag=false;
		String sql="insert into emp(empno,ename,job,hiredate,sal)values (?,?,?,?,?)";
		this.pstmt=this.conn.prepareStatement(sql);
		this.pstmt.setInt(1,emp.getEmpno());
		this.pstmt.setString(2, emp.getEname());
		this.pstmt.setString(3, emp.getJob());
		this.pstmt.setDate(4, new java.sql.Date(emp.getHiredate().getTime()));
		this.pstmt.setFloat(5, emp.getSal());
		if(this.pstmt.executeUpdate()>0){
			flag=true;
		}
		this.pstmt.close();
		return flag;
	}

	@Override
	public List<Emp> findAll(String keyWord) throws Exception {
		List<Emp> all=new ArrayList<Emp>();
		String sql="select empno,ename,job,hiredate,sal from emp where ename like ? or job like ?";
		this.pstmt=this.conn.prepareStatement(sql);
		this.pstmt.setString(1, "%"+keyWord+"%");
		this.pstmt.setString(2, "%"+keyWord+"%");
		ResultSet rs=this.pstmt.executeQuery();
		Emp emp=null;
		while(rs.next()){
			emp=new Emp();
			emp.setEmpno(rs.getInt(1));
			emp.setEname(rs.getString(2));
			emp.setJob(rs.getString(3));
			emp.setHiredate(rs.getDate(4));
			emp.setSal(rs.getFloat(5));
			all.add(emp);
		}
		this.pstmt.close();
		return all;
	}

	@Override
	public Emp findById(int empno) throws Exception {
		Emp emp=null;
		String sql="select empno,ename,job,hiredate,sal from emp where empno=?";
		this.pstmt=this.conn.prepareStatement(sql);
		this.pstmt.setInt(1, empno);
		ResultSet rs=this.pstmt.executeQuery();
		if(rs.next()){
			emp=new Emp();
			emp.setEmpno(rs.getInt(1));
			emp.setEname(rs.getString(2));
			emp.setJob(rs.getString(3));
			emp.setHiredate(rs.getDate(4));
			emp.setSal(rs.getFloat(5));
		}
		this.pstmt.close();
		return emp;
	}
		
}

五.代理主题实现类——EmpDAOProxy.java

该类实现了IEmpDAO,是对数据库中数据直接操作类。

该类获取了数据库的连接,同时也负责关闭数据库。并且调用真实实现类(即EmpDAOImpl类)对象的的方法进行数据库操作。

package com.fcy.dao.proxy;

import java.util.List;

import com.fcy.dao.IEmpDAO;
import com.fcy.dao.impl.EmpDAOImpl;
import com.fcy.dbc.DatabaseConnection;
import com.fcy.vo.Emp;

public class EmpDAOProxy implements IEmpDAO{
	
	private DatabaseConnection dbc =null;
	private IEmpDAO dao =null;
	
	public EmpDAOProxy() throws Exception{
		this.dbc=new DatabaseConnection();
		this.dao=new EmpDAOImpl(this.dbc.getConnection());
	}
	
	public boolean doCreate(Emp emp) throws Exception{
		boolean flag=false;
		try{
			if(this.dao.findById(emp.getEmpno())==null){
				flag=this.dao.doCreate(emp);
			}
		}catch(Exception e){
			throw e;
		}finally{
			this.dbc.close();
		}
		return flag;
	}
	
	public List<Emp> findAll(String keyWord) throws Exception{
		List<Emp> all=null;
		try{
			all=this.dao.findAll(keyWord);
		}catch(Exception e){
			throw e;
		}finally{
			this.dbc.close();
		}
		return all;
	}
	
	public Emp findById(int empno) throws Exception{
		Emp emp=null;
		try{
			emp=this.dao.findById(empno);
		}catch(Exception e){
			throw e;
		}finally{
			this.dbc.close();
		}
		return emp ;
	}
}

六.DAO工厂类——DAOFactory.java

该类包含一个静态方法getIEmpDAOInstance(),返回的值是IEmpDAO,用来取得DAO的实例化对象。

package com.fcy.dao.factory;

import com.fcy.dao.IEmpDAO;
import com.fcy.dao.proxy.EmpDAOProxy;

public class DAOFactory {

	public static IEmpDAO getIEmpDAOInstance() throws Exception{
		return new EmpDAOProxy();
	}
	
}

七.编写测试类:

package com.fcy.dao.test;

import com.fcy.dao.factory.DAOFactory;
import com.fcy.vo.Emp;

public class Test {
	public static void main(String args[]) throws Exception{
		//按Id查找
		DAOFactory.getIEmpDAOInstance().findById(2);
		
		//查找包含关键字的全部记录
		DAOFactory.getIEmpDAOInstance().findAll("张三");
		
		//增加记录
		Emp emp=null;
		for(int x=0;x<5;x++){
			emp =new Emp();
			emp.setEmpno(100+x);
			emp.setEname("张三-"+x);
			emp.setJob("老师-"+x);
			emp.setHiredate(new java.util.Date());
			emp.setSal(500*x);
			DAOFactory.getIEmpDAOInstance().doCreate(emp);
		}
	}
}

在之后的代码编写中,凡是要用到数据库操作的地方,只需要加上
DAOFactory.getIEmpDAOInstance().相应功能的函数名

即可。


八.问题与讨论:

对于有的读者可能纳闷,写了这么一大段代码,与之前把所有的操作写在一个类中,代码多了好多,似乎把代码复杂化了,现对该设计模式进行如下说明:


1.代码中的包:

该设计模式中共用到了6个包:

com.fcy.dbc:该类包用来存放数据库打开与关闭操作的类。实际项目中,可能会有多个不同的数据库,可以为每个数据库写一个类。

com.fcy.vo:用来存放vo类,一张表对应一个vo类。

com.fcy.dao:存放dao操作接口,一张表对应一个操作接口。

com.fcy.dao.impl:存放真实主题实现类类,实现dao操作接口,同样一张表对应一个impl。

com.fcy.dao.proxy:存放代理类,同样实现了dao操作接口,也是一张表对应一个proxy。

com.fcy.dao.factory:存放工厂类,用来生成dao对象。此包中只有一个类DAOFactory,类中的每一个方法都是静态方法,且都返回一个DAO,


2.代理设计的好处:

有人可能会有疑问,impl与proxy明明可以用一个类来完成,为什么要写两个呢?其实,这样做主要是为了降低代码的耦合度,避免代码高度耦合。

关于耦合度说明:在软件设计中,每个模块应尽量保持独立,这样才能使模块复用性达到最大,同时若有一个模块需要改变,其他模块需要做的改变才能最小。这种描述代码模块间独立程度的术语就是耦合度。


3.工厂设计的好处:

工厂类DAOFactory中,函数都用static进行声明,这样做避免了创建对象。在后续的操作中,只需直接调用即可,不需要考虑构造函数的结构。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值