范型 DAO范型的应用

当你偶然路过这里时,我假定你已经很明白 java 中范型和 DAO 模式了。当然,我也会顺便唠叨几句范型和 DAO 模式,只是它们不会这篇随笔的重点。我早先在 DW 上看到一篇蛮不错的文章 不要重复 DAOHibernate Spring AOP 构建泛型类型安全的 DAO ,它也促使我在一个实验工程中使用了范型化的 DAO 模式。前几天看到的另一篇文章 Generic Data Access Objects 使我重新想起了这档事。以前的代码不可追,索性就重做了一个 sample 实现范型化的 DAO 。坦白的讲,和上面的两篇文章相比,这篇随笔并没有太多新内容,如果你愿意的话,你可以只看上面的两篇文章而关掉这个页面。

先说说范型。自从 java5 引入范型后,它就成为我代码中不可少的一部分。在没有范型以前,强制转换充斥于文件的各个角落,不单代码不易于阅读,时不时的会出现转换异常。就像你所经历的,对于集合类中的对象,如果显示声明的话,安全性和阅读性都大大提高。总之啦,范型是个很有用的东西。

       再说说 DAO 模式。 Java EE 中,最经典的架构模式就是三层架构或多层架构。而数据持久化层,流行的就是 DAO 模式。尽管很多人批评这种 贫血模型 OO ,但使用上的方便使得 DAO 模式很受程序员喜爱。想一想 Spring 框架吧,支持 DAO 模式的典型框架,数据与操作的分离,使得 IOC AOP 等技术灵活的运转起来。说到底,理论和实践并不是完全统一的,为了满足实际的需要,有时不得不做些折衷。

好了,该说说我做的一个小例子。其实范型化的 DAO 就是给出一个抽象的 DAO 及其实现,实现的内容就是基本的 CRUD 操作。闲言少叙,开始我的代码。

范型的 DAO 接口,包含基本的 CRUD 操作。 GenericDAO 的实现,通过 Spring 模板实现了 CRUD 操作。

import  java.util. * ;
import  java.io. * ;

public   interface  GenericDAO < T, PK  extends  Serializable >   {

    T findById(PK id
);

    List
< T >  findAll();

    
void  insert(T entity);
    
    
void  update(T entity);

    
void  delete(T entity);
}
      
  package  org.prague.dao.hibernate;

import  java.util. * ;
import  java.io. * ;
import  org.hibernate.Session;
import  org.hibernate.SessionFactory;
import  org.springframework.orm.hibernate3.HibernateTemplate;
import  org.prague.dao.GenericDAO;
import  java.lang.reflect. * ;

public   abstract   class  GenericHibernateDAO < T, PK  extends  Serializable >
        
implements  GenericDAO < T, PK >   {

    
private HibernateTemplate hibernateTemplate;
    
private Class<T> type;
    
    
public GenericHibernateDAO(){
        
this.type = (Class<T>)((ParameterizedType)(this.getClass().getGenericSuperclass()))
                            .getActualTypeArguments()[
0];
    }

    
    
public void setSessionFactory(SessionFactory sessionFactory){
        
this.hibernateTemplate = new HibernateTemplate(sessionFactory);
    }

    
    
public void delete(T entity) {
        
this.hibernateTemplate.delete(entity);
    }

    
    

    
public List<T> findAll() {
        String hql 
= "from "+this.type.getSimpleName();
        
return (List<T>)this.hibernateTemplate.find(hql);
    }


    
public T findById(PK id{
        
return (T)this.hibernateTemplate.get(type, id);
    }


    
public void insert(T entity) {
        
this.hibernateTemplate.save(entity);
    }


    
public void update(T entity) {
        
this.hibernateTemplate.update(entity);
    }

    
    
protected Session getSession(){
        
return this.hibernateTemplate.getSessionFactory().getCurrentSession();
    }

    
    
protected HibernateTemplate getHibernateTemplate(){
        
return this.hibernateTemplate;
    }

    
}
      

如果不用Spring的话,Hibernate也能轻松的实现这些操作。但坦白的讲,这些操作并不实用。对于不同的实体,可能不会调用这些操作或是调用的操作不完全相同。比如说,对于查询数据表中的数据列表,可能的情况是要求查询条件中按照某些字段排序。如果想给出一个通用的实现方法,接口中不可避免的要包含查询条件,比如说包含一个Hibernate中的条件查询对象。但这样话,就需要在Service层构造查询条件,还不如直接写个方法来的实在。
   

下面就是一个具体的DAO及实现。

import  org.prague.domain. * ;

public   interface  AccountDAO  extends  GenericDAO < Account,Long > {
    
public Account findByNameAndPwd(String name,String pwd);
}

 


package  org.prague.dao.hibernate;

import  java.util.List;

import  org.prague.dao.AccountDAO;
import  org.prague.domain.Account;
import  org.springframework.orm.hibernate3.HibernateCallback;
import  org.springframework.orm.hibernate3.HibernateTemplate;

public   class  AccountHibernateDAO  extends  GenericHibernateDAO < Account,Long >   implements
        AccountDAO 
{

    
public Account findByNameAndPwd(final String name, final String pwd) {
        
final String hql  = "from Account where name=:name and pwd=:pwd";
        
/*
        List list = (List)this.getHibernateTemplate().executeFind(new HibernateCallback(){
            public Object doInHibernate(Session s) throws HibernateException, SQLException {
                return s.createQuery(hql).setString("name", name).setString("pwd", pwd).list();
            }
        });
        
*/

        List
<Account> list = (List<Account>)this.getHibernateTemplate().findByNamedParam(hql, 
                
new String[]{"name","pwd"}new String[]{name,pwd});
        
if(list!=null && !list.isEmpty()){
            
return list.get(0);
        }

        
return null;
    }

}

       当然少不了实体bean了,尽管它很简单。

package  org.prague.domain;

import  java.io.Serializable;

public   abstract   class  AbstractDomain < PK  extends  Serializable > {
    
protected PK id;

    
    
public PK getId() {
        
return id;
    }


    
public void setId(PK id) {
        
this.id = id;
    }


}


package  org.prague.domain;

public   class  Account  extends  AbstractDomain < Long > {
    
private String name;
    
private String pwd;
    
    
public String getName() {
        
return name;
    }

    
public void setName(String name) {
        
this.name = name;
    }

    
public String getPwd() {
        
return pwd;
    }

    
public void setPwd(String pwd) {
        
this.pwd = pwd;
    }

    @Override
    
public String toString() {
        
return "Account: id="+this.id+" name="+this.name+" pwd="+this.pwd+"/n";
    }

    
}

       想要程序运行起来,还需要配置文件的作用,这里列出Account对应的Hibernate映射文件和Spring配置文件。由于该Sample没有Service层的概念,因此DAO需要声明性事务的作用。

xml version='1.0' encoding='UTF-8' ?>
DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>

< hibernate-mapping  package ="org.prague.domain" >
    
< class  name ="Account"  table ="Account" >
        
< id  name ="id"  column ="id"  type ="java.lang.Long" >
            
< generator  class ="identity" > generator >
        
id >
        
< property  name ="name"  column ="name" > property >
        
< property  name ="pwd"  column ="pwd" > property >
    
class >
hibernate-mapping >

 

xml version="1.0" encoding="UTF-8" ?>
DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd" >
< beans  default-lazy-init ="true" >

    
< bean  id ="sessionFactory"
        class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean" >
        
< property  name ="configLocation" >
            
< value > classpath:hibernate.cfg.xml value >
        
property >
    
bean >

    
< bean  name ="transactionManager"
        class
="org.springframework.orm.hibernate3.HibernateTransactionManager" >
        
< property  name ="sessionFactory" >
            
< ref  bean ="sessionFactory"   />
        
property >
    
bean >

    
< bean  id ="baseTransactionProxy"
        class
="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
        abstract
="true" >
        
< property  name ="transactionManager"  ref ="transactionManager"   />
        
< property  name ="transactionAttributes" >
            
< props >
                
< prop  key ="get*" > PROPAGATION_REQUIRED,readOnly prop >
                
< prop  key ="*" > PROPAGATION_REQUIRED prop >
            
props >
        
property >
    
bean >

    
< bean  id ="accountDAO"  parent ="baseTransactionProxy" >
        
< property  name ="target" >
            
< bean  class ="org.prague.dao.hibernate.AccountHibernateDAO" >
                
< property  name ="sessionFactory" >
                    
< ref  bean ="sessionFactory"   />
                
property >
            
bean >
        
property >
    
bean >
beans >

       再多说几句吧。我以前写过一个程序,在GenericDAO中给出了更多的方法,比如:

public  List < T >  findListBy(String expression);
    
public   void  deleteBy(String expression);
    
public   void  updateBy(String expression);

    我的想法和做法是不言而喻的。当时想通过在GenericDAO中声明这样的公共方法,简化DAO中操作。那是我还不是很清楚Hibernate中的Creteria,就实现一个类似于Hibernate Creteria包的东西,通过在Service层中构造Creteria对象并得到一个拼接后的hql语句,然后调用上面的这几个方法。通过上面的几个方法,基本上满足了DAO层的操作。但问题是,我不得不在Service层构建CreteriaService因此显得臃肿异常,而DAO层就单薄得很。好好的想一想,这样的结果不过是变相的将DAO层和Service层合并了。依我的想法,刻意的追求公共数据库操作并不一定实用。即便是这个例子,如果不使用Hibernate框架,而是使用JDBCIbatis等,GenericDAO 中的方法是很难以通用的方式实现的。你不得不做的就是,每个继承自 GenericDAODAO,都需要单独的实现基本的CRUD操作。  

 

你可能感兴趣的:(范型 DAO范型的应用)