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层设计。
第一个设计版本:增加BaseDao、BaseDaoImpl,抽取公共操作
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中传入字节码了,大大方便了编程。
- 本文固定链接: http://www.flyne.org/article/628
- 转载请注明: 东风化宇 2014年09月01日 于 Flyne 发表
你好,太厉害了
宇哥,牛逼
学习了
华而不实
灰常牛逼
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; } //其他部分代码不变 ……}