Thinking in sky

          --老賀的BLOG

            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            21 隨筆 :: 0 文章 :: 35 評(píng)論 :: 0 Trackbacks
              因?yàn)镾pring自帶的sample離我們的實(shí)際項(xiàng)目很遠(yuǎn),所以官方一點(diǎn)的model層模式展現(xiàn)就靠Appfuse了。

              但Appfuse的model層總共有一個(gè)DAO接口、一個(gè)DAOImpl類(lèi)、一個(gè)Service接口、一個(gè)ServiceImpl類(lèi)、一個(gè)DataObject.....大概只有受慣了虐待的人才會(huì)欣然接受吧。
              另外,Domain-Driven逢初一、十五也會(huì)被拿出來(lái)討論一遍。

              其實(shí)無(wú)論什么模式,都不過(guò)是一種人為的劃分、抽象和封裝。只要在團(tuán)隊(duì)里理解一致,自我感覺(jué)優(yōu)雅就行了。
               我的建議是,一開(kāi)始DO和Manager一生一旦包演全場(chǎng),DO作為純數(shù)據(jù)載體,而Manager類(lèi)放置商業(yè)方法,用 getHibernateTemplate()直接訪問(wèn)數(shù)據(jù)庫(kù),不強(qiáng)制基于接口編程。當(dāng)某天系統(tǒng)復(fù)雜到你直覺(jué)上需要將DAO層和Service層分開(kāi)時(shí),再分開(kāi)就好了。

              1.DataObject類(lèi)
              
          好聽(tīng)點(diǎn)也可以叫Domain Object。Domain Driven  Development雖然誘人,但因?yàn)镴ava下的ORM框架都是基于Data Mapper模式的,沒(méi)有Ruby On Rails中那種Active Recorder的模式。所以,還是壓下了這個(gè)欲望,Data Object純粹作一個(gè)數(shù)據(jù)載體,而把數(shù)據(jù)庫(kù)訪問(wèn)與商業(yè)邏輯操作統(tǒng)一放到Manager類(lèi)中。

              2.Manager類(lèi)
              我的Manager類(lèi)是Appfuse中DAO類(lèi)與Service類(lèi)的結(jié)合體,因?yàn)椋?br>
              2.1 不想使用純DAO
               以往的DAO是為了透明不同數(shù)據(jù)庫(kù)間的差異,而現(xiàn)在Hibernate已經(jīng)做的很好。所以目前純DAO的更大作用是為了將來(lái)可以切換到別的ORM方案比如 iBatis,但一個(gè)Pragmaic的程序員顯然不會(huì)無(wú)聊到為了這個(gè)機(jī)會(huì)不大的理由,現(xiàn)在就去做一個(gè)純DAO層,項(xiàng)目又不是Appfuse那樣為了 demo各種ORM方案而存在。

              2.2 也不想使用Service層來(lái)為Dao解耦
              在JPetStore里有一個(gè)很薄的Service層,F(xiàn)ascade了一堆DAO類(lèi),把這些DAO類(lèi)的所有方法都僵硬的重復(fù)了一遍。理論上一個(gè) Manager類(lèi)可以管理數(shù)個(gè)Dao類(lèi),可以避免Dao之間直接耦合。但既然有Manager的情況下,商業(yè)邏輯都是寫(xiě)在Manager類(lèi)的,那樣子 Manager似乎還是調(diào)用另一個(gè)Manager比較妥當(dāng),調(diào)用裸Dao可能存在忽略了某些邏輯。所以,耦合又從Dao層升到Service層了。
               所以,除非你做的是超薄的不帶邏輯的Service層,否則沒(méi)有解耦的意義。
              何況,對(duì)一個(gè)不是死搬書(shū)的Designer來(lái)說(shuō),組件邊界之內(nèi)的類(lèi)之間的耦合并不是耦合。

              3.去除不必要的基于接口編程
              眾所周知,Spring是提倡基于接口編程的。
              但有些Manager類(lèi),比如SaleOrderManager ,只有5%的機(jī)會(huì)再有另一個(gè)Impl實(shí)現(xiàn)。95%時(shí)間里這兩兄弟站一起,就像C++里的.h和.cpp,徒增維護(hù)的繁瑣(經(jīng)常要同步兩個(gè)文件的函數(shù)聲明),和代碼瀏覽跳轉(zhuǎn)時(shí)的不便(比如從Controler類(lèi)跟蹤到Service類(lèi)時(shí),只能跳轉(zhuǎn)到接口類(lèi)的相應(yīng)函數(shù),還要再按一次復(fù)雜的熱鍵才跳轉(zhuǎn)到實(shí)現(xiàn)類(lèi))
              連Martin Flower都說(shuō),強(qiáng)制每個(gè)類(lèi)都分離接口和實(shí)現(xiàn)是過(guò)猶不及。只在有多個(gè)獨(dú)立實(shí)現(xiàn),或者需要消除對(duì)實(shí)現(xiàn)類(lèi)的依賴時(shí),才需要分離接口。

              3.1 DAO被強(qiáng)制用接口的原因
              Spring IOC本身是不會(huì)強(qiáng)制基于接口的,但DAO類(lèi)一般要使用Spring的聲明式事務(wù)機(jī)制,而聲明式的事務(wù)機(jī)制是使用Spring AOP來(lái)實(shí)現(xiàn)的。Spring AOP的實(shí)現(xiàn)機(jī)制包括動(dòng)態(tài)代理和Cgilib2,其中Spring AOP默認(rèn)使用的Java動(dòng)態(tài)代理是必須基于接口,所以就要求基于接口了。
              
              3.2 解決方法
              那就讓Spring AOP改用CGLib2,生成目標(biāo)類(lèi)的子類(lèi)吧,我們只要指定使用聲明式事務(wù)的FactoryBean使用CGLib的方式來(lái)實(shí)現(xiàn)AOP,就可以不基于接口編程了。
              指定的方式為設(shè)置proxyTargetClass為true。如下:
          <bean class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
          id
          ="baseService"   abstract="true">
            
          <property name="transactionManager" ref="transactionManager"/>
            
          <property name="proxyTargetClass" value="true"/>

          </bean>


          又因?yàn)檫@些Service Bean都是單例,效率應(yīng)該不受影響。

              4.總結(jié)
              對(duì)比Appfuse里面的5個(gè)類(lèi),我的Model層里只有VO作為純數(shù)據(jù)載體,Manager類(lèi)放商業(yè)方法。有人說(shuō)這樣太簡(jiǎn)單了,但一個(gè)應(yīng)用,要?jiǎng)澇蓭讉€(gè) JSP,一個(gè)Controller,一個(gè)Manager,一個(gè)VO,對(duì)我來(lái)說(shuō)已經(jīng)足夠復(fù)雜,再要往上架墻疊屋,恕不奉陪,起碼在我的項(xiàng)目范圍里不需要。 (但有很多項(xiàng)目是需要的,神佑世人)

              后記:迫于世人的壓力,SpringSide暫時(shí)還是把DAO和Service層分開(kāi)了,但依然堅(jiān)持不搞那么多接口。
          另外,盡量利用IDEA的代碼生成熱鍵,為Manager類(lèi)生成delegate的Dao類(lèi)方法。 



          轉(zhuǎn)自http://blog.csdn.net/qking93415981/archive/2007/08/08/1731676.aspx
          posted on 2007-08-24 09:58 老賀 閱讀(623) 評(píng)論(3)  編輯  收藏 所屬分類(lèi): J2EE框架

          評(píng)論

          # re: 簡(jiǎn)化Spring(2)--Model層 2007-08-24 10:06 小賀
          現(xiàn)在的SpringSide 2.0是把DAO和Service合在一起的,不知道以前的版本是怎么做的。 合在一起的類(lèi)叫做Manager,繼承自范型的DAO,如

          public class UserManager extends HibernateEntityDao<User> {
          // ....CRUD以外的其它商業(yè)方法
          }

          以前DAO里的CRUD等基本方法,現(xiàn)在放在了Manager類(lèi)里而且是不可見(jiàn)的(因?yàn)槭抢^承過(guò)來(lái)的),這樣Manager里直接寫(xiě)以前Service里的商業(yè)方法,看起來(lái)就很清晰了。

          由于采用范型DAO,我們就不需要去寫(xiě)具體的DAO實(shí)現(xiàn),編碼量就因此減少了很多。  回復(fù)  更多評(píng)論
            

          # re: 簡(jiǎn)化Spring(2)--Model層 2007-08-24 10:13 小賀
          以前做畢業(yè)設(shè)計(jì)時(shí),仿照Appfuse的做法,model層總共有一個(gè)DAO接口、一個(gè)DAOImpl類(lèi)、一個(gè)Service接口、一個(gè)ServiceImpl類(lèi)、一個(gè)DataObject,寫(xiě)起來(lái)確實(shí)很麻煩,本來(lái)寫(xiě)的就是個(gè)小系統(tǒng)。

          小系統(tǒng)嘛還是SpringSide的Model層簡(jiǎn)潔又清晰。其實(shí)Appfuse的DAO和Service的概念在SpringSide里還是有的,只是SpringSide把DAO和Service合成了一個(gè)Manager。  回復(fù)  更多評(píng)論
            

          # re: 簡(jiǎn)化Spring(2)--Model層[未登錄](méi) 2008-03-18 10:04 vulcan
          google到你的文章,發(fā)現(xiàn)我們對(duì)于DAO層和Service層的設(shè)計(jì)想法有些一樣。
          http://vulcan.javaeye.com/admin/blogs/160823
          但是我遇到一個(gè)問(wèn)題,不知道你遇到過(guò)沒(méi)有,如果要直接對(duì)從范型接口繼承來(lái)的方法簽名進(jìn)行聲明式事務(wù),卻總不能成功。不知道兄弟有沒(méi)有類(lèi)似的問(wèn)題,還是有其他的解決方法?我加你QQ,請(qǐng)教一下。  回復(fù)  更多評(píng)論
            

          主站蜘蛛池模板: 确山县| 化德县| 左贡县| 台州市| 佛山市| 墨脱县| 洪洞县| 绥中县| 罗源县| 卫辉市| 白城市| 乐清市| 南通市| 沿河| 阿坝县| 信丰县| 鄯善县| 澄城县| 菏泽市| 花莲县| 漯河市| 哈巴河县| 南丹县| 方正县| 平昌县| 乌拉特后旗| 文成县| 宁波市| 澄迈县| 建水县| 专栏| 宜章县| 陕西省| 宜良县| 古浪县| 武威市| 昌宁县| 娄底市| 砀山县| 寿阳县| 普格县|