首页 > WEB开发 > 后台开发 > DAO层设计(泛型反射)
2014
09-01

DAO层设计(泛型反射)

06. DAO层设计(泛型反射)13

DAO层主要完成对数据库的CRUD操作,大部的DAO接口中都有增删改、查一条记录的操作,如下面的CustomerDao和BookDao接口定义:

public interface CustomerDao {
	void add(Customer c);//增
	void delete(Integer customerId);//删
	void update(Customer c);//改
	Customer findOne(Integer customerId);//查一条记录

	//分页查询
	List<Customer> findMulti(int offset,int count);
}

public interface BookDao {
	void add(Book b);//增
	void delete(String bookId);//删
	void update(Book b);//改
	Book findOne(Integer bookId);//查一条记录
}

因此考虑对这4个操作进行抽取,达到代码复用的目的。由于不同的DAO对应的实体不一样,需用到泛型的知识。下面给出了两个版本的DAO层设计。

第一个设计版本:增加BaseDaoBaseDaoImpl,抽取公共操作

public interface BaseDao<T> {
	void add(T t);//增
	void delete(Serializable id);//删
	void update(T t);//改
	T findOne(Serializable id);//查一条记录
}

//为了代码的简练,下面具体的实现用了Hibernate,不过思想都是一样的
public class BaseDaoImpl<T> implements Dao<T> {
	//findOne操作需要各个实体类对应的字节码,由具体XxxDaoImpl传入
	private Class clazz;
	public BaseDao(Class clazz){
		this.clazz = clazz;
	}

	public void add(T t) {//增
		Session s = HibernateUtil.getSession();
		Transaction tx = s.beginTransaction();
		s.save(t);
		tx.commit();
		s.close();
	}

	public T findOne(Serializable id) {//查一条记录
		Session s = HibernateUtil.getSession();
		T t = (T)s.get(clazz, id);
		s.close();
		return t;
	}

	public void delete(Serializable id) {//删
		Session s = HibernateUtil.getSession();
		T t = (T)s.get(clazz, id);
		Transaction tx = s.beginTransaction();
		s.delete(t);
		tx.commit();
		s.close();
	}

	public void update(T t) {//改
		Session s = HibernateUtil.getSession();
		Transaction tx = s.beginTransaction();
		s.update(t);
		tx.commit();
		s.close();
	}
}

当使用了BaseDao和BaseDaoImpl对公共操作进行了抽取后,在设计CustomerDao、BookDao等DAO层代码时变得相当简练,只需要在这四个操作的基础上增加自己独有的操作即可。如下:

public interface CustomerDao extends BaseDao<Customer>{
	//分页查询
	List<Customer> findRecords(int offset,int count);
}
public class CustomerDaoImpl extends BaseDaoImpl<Customer> implements CustomerDao{
	//BaseDaoImpl中需要传入具体实体类的Class字节码
	public CustomerDaoImpl(Class clazz) {
		super(Customer.class);
	}

	public List<Customer> findRecords(int offset, int count) {
		return null;//只是为了讲解DAO层设计,具体实现省略
	}
}

public interface BookDao extends BaseDao<Book> {
}

public class BookDaoImpl extends BaseDaoImpl<Book> implements BookDao {
	public BookDaoImpl(Class clazz) {
		super(Book.class);
	}
}

第一个版本的代码在CustomerDaoImpl、BookDaoImpl中还需要传入操作的实体类的字节码,其实这部分的代码是完全可以避免的。解决办法是利用泛型反射在BaseDaoImpl中搞到对应实体类的字节码。见下面的第二个版本:

第二个设计版本:利用泛型反射在BaseDaoImpl中搞到实体类的字节码。

public class BaseDaoImpl<T> implements BaseDao<T> {
	private Class clazz;

	public BaseDaoImpl(){
		//利用泛型的反射在实例化时拿到实体类的字节码
		Type t = this.getClass().getGenericSuperclass();
		ParameterizedType pt =  (ParameterizedType)t;
		Type actualType = pt.getActualTypeArguments()[0];
		clazz = (Class)actualType;
	}
	//其他部分代码不变
	……
}

由于直接在BaseDaoImpl中拿到了实体类的字节码,因此不需要在XxxDaoImpl中传入字节码了,大大方便了编程。


DAO层设计(泛型反射)》有 6 条评论

  1. 刘晓伟 说:

    你好,太厉害了

  2. kevin 说:

    宇哥,牛逼

  3. 竹木蜻蜓 说:

    学习了

  4. D 说:

    华而不实

  5. 彩云追月 说:

    public class BaseDaoImpl implements BaseDao { private Class clazz; public BaseDaoImpl(){ //利用泛型的反射在实例化时拿到实体类的字节码 Type t = this.getClass().getGenericSuperclass(); ParameterizedType pt = (ParameterizedType)t; Type actualType = pt.getActualTypeArguments()[0]; clazz = (Class)actualType; } //其他部分代码不变 ……}

留下一个回复

你的email不会被公开。