邊城愚人

          如果我不在邊城,我一定是在前往邊城的路上。

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            31 隨筆 :: 0 文章 :: 96 評論 :: 0 Trackbacks

          當(dāng)你偶然路過這里時,我假定你已經(jīng)很明白 java 中范型和 DAO 模式了。當(dāng)然,我也會順便嘮叨幾句范型和 DAO 模式,只是它們不會這篇隨筆的重點。我早先在 DW 上看到一篇蠻不錯的文章 不要重復(fù) DAOHibernate Spring AOP 構(gòu)建泛型類型安全的 DAO ,它也促使我在一個實驗工程中使用了范型化的 DAO 模式。前幾天看到的另一篇文章 Generic Data Access Objects 使我重新想起了這檔事。以前的代碼不可追,索性就重做了一個 sample 實現(xiàn)范型化的 DAO 。坦白的講,和上面的兩篇文章相比,這篇隨筆并沒有太多新內(nèi)容,如果你愿意的話,你可以只看上面的兩篇文章而關(guān)掉這個頁面。

          先說說范型。自從 java5 引入范型后,它就成為我代碼中不可少的一部分。在沒有范型以前,強制轉(zhuǎn)換充斥于文件的各個角落,不單代碼不易于閱讀,時不時的會出現(xiàn)轉(zhuǎn)換異常。就像你所經(jīng)歷的,對于集合類中的對象,如果顯示聲明的話,安全性和閱讀性都大大提高。總之啦,范型是個很有用的東西。

          ?????? 再說說 DAO 模式。 Java EE 中,最經(jīng)典的架構(gòu)模式就是三層架構(gòu)或多層架構(gòu)。而數(shù)據(jù)持久化層,流行的就是 DAO 模式。盡管很多人批評這種 貧血模型 OO ,但使用上的方便使得 DAO 模式很受程序員喜愛。想一想 Spring 框架吧,支持 DAO 模式的典型框架,數(shù)據(jù)與操作的分離,使得 IOC AOP 等技術(shù)靈活的運轉(zhuǎn)起來。說到底,理論和實踐并不是完全統(tǒng)一的,為了滿足實際的需要,有時不得不做些折衷。

          好了,該說說我做的一個小例子。其實范型化的 DAO 就是給出一個抽象的 DAO 及其實現(xiàn),實現(xiàn)的內(nèi)容就是基本的 CRUD 操作。閑言少敘,開始我的代碼。

          范型的 DAO 接口,包含基本的 CRUD 操作。 GenericDAO 的實現(xiàn),通過 Spring 模板實現(xiàn)了 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也能輕松的實現(xiàn)這些操作。但坦白的講,這些操作并不實用。對于不同的實體,可能不會調(diào)用這些操作或是調(diào)用的操作不完全相同。比如說,對于查詢數(shù)據(jù)表中的數(shù)據(jù)列表,可能的情況是要求查詢條件中按照某些字段排序。如果想給出一個通用的實現(xiàn)方法,接口中不可避免的要包含查詢條件,比如說包含一個Hibernate中的條件查詢對象。但這樣話,就需要在Service層構(gòu)造查詢條件,還不如直接寫個方法來的實在。
          ???

          下面就是一個具體的DAO及實現(xiàn)。

          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<Account>?list?=?(List<Account>)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;
          ????}

          }

          ???????當(dāng)然少不了實體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對應(yīng)的Hibernate映射文件和Spring配置文件。由于該Sample沒有Service層的概念,因此DAO需要聲明性事務(wù)的作用。

          <?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);

          ??? 我的想法和做法是不言而喻的。當(dāng)時想通過在GenericDAO中聲明這樣的公共方法,簡化DAO中操作。那是我還不是很清楚Hibernate中的Creteria,就實現(xiàn)一個類似于Hibernate Creteria包的東西,通過在Service層中構(gòu)造Creteria對象并得到一個拼接后的hql語句,然后調(diào)用上面的這幾個方法。通過上面的幾個方法,基本上滿足了DAO層的操作。但問題是,我不得不在Service層構(gòu)建CreteriaService因此顯得臃腫異常,而DAO層就單薄得很。好好的想一想,這樣的結(jié)果不過是變相的將DAO層和Service層合并了。依我的想法,刻意的追求公共數(shù)據(jù)庫操作并不一定實用。即便是這個例子,如果不使用Hibernate框架,而是使用JDBCIbatis等,GenericDAO 中的方法是很難以通用的方式實現(xiàn)的。你不得不做的就是,每個繼承自 GenericDAODAO,都需要單獨的實現(xiàn)基本的CRUD操作。??

          ?

          posted on 2007-04-17 08:55 kafka0102 閱讀(3599) 評論(7)  編輯  收藏 所屬分類: Pattern

          評論

          # re: 要范型,要DAO,更要范型DAO[未登錄] 2007-04-17 09:07 Matthew
          朋友,把排版重搞一下吧!  回復(fù)  更多評論
            

          # re: 要范型,要DAO,更要范型DAO 2007-04-17 09:20 kafka0102
          都要瘋掉了。昨晚第一遍寫的時候,直接在編輯器里做,結(jié)果添加代碼框出不來,IE死掉了。第二遍在word里寫,結(jié)果發(fā)表時不能連接服務(wù)器。好吧,一大早來做,結(jié)果從word到編輯器轉(zhuǎn)換時,格式都亂了。就這樣了,沒心情再改了。  回復(fù)  更多評論
            

          # re: 要范型,要DAO,更要范型DAO 2007-04-17 10:32 CrossAge
          這樣子做,還有必要搞DAO這一層么?
          目的就是為了節(jié)省CRUD的代碼量?  回復(fù)  更多評論
            

          # re: 要范型,要DAO,更要范型DAO 2007-04-18 08:40 開源英漢機器翻譯
          開源英漢機器翻譯C#.NET項目 www.liebiao.net

          我們邀請你 技術(shù)交流  回復(fù)  更多評論
            

          # re: 要范型,要DAO,更要范型DAO[未登錄] 2007-04-27 13:20 Diego
          樓主,你博客上的的代碼折疊功能是用什么工具生成的?我問了好幾個人都不知道,我也想要這個功能  回復(fù)  更多評論
            

          # re: 要范型,要DAO,更要范型DAO 2007-05-03 22:06 kafka0102
          發(fā)表文章時,代碼不是直接貼進去的,而是選擇編輯器中的“代碼”選項(應(yīng)該在編輯菜單的最后一個位置),然后根據(jù)彈出來的對話框進行操作就行了。  回復(fù)  更多評論
            

          # re: 要范型,要DAO,更要范型DAO 2008-10-31 11:14 天山劍
          需要一個范型dao,

          上面的有問題,測試不了

          有沒有測通的

          請高手指點

          QQ:328152797

            回復(fù)  更多評論
            


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 万全县| 汶上县| 贺州市| 武鸣县| 崇义县| 抚顺县| 宁德市| 芦溪县| 平武县| 云霄县| 徐闻县| 焦作市| 密云县| 左贡县| 六枝特区| 江门市| 明溪县| 吴忠市| 湖南省| 邵武市| 阿坝| 修武县| 温宿县| 淮滨县| 云阳县| 景谷| 锡林郭勒盟| 米泉市| 临西县| 洪泽县| 内乡县| 公安县| 那坡县| 北海市| 都兰县| 余庆县| 平果县| 南汇区| 河西区| 六盘水市| 龙南县|