posts - 89,  comments - 98,  trackbacks - 0

          既然大家都統一了觀點,那么就有了一個很好的討論問題的基礎了。Martin Fowler的Domain Model,或者說我們的第二種模型難道是完美無缺的嗎?當然不是,接下來我就要分析一下它的不足,以及可能的解決辦法,而這些都來源于我個人的實踐探索。

          在第二種模型中,我們可以清楚的把這4個類分為三層:

          1、實體類層,即Item,帶有domain logic的domain object
          2、DAO層,即ItemDao和ItemDaoHibernateImpl,抽象持久化操作的接口和實現類
          3、業務邏輯層,即ItemManager,接受容器事務控制,向Web層提供統一的服務調用

          在這三層中我們大家可以看到,domain object和DAO都是非常穩定的層,其實原因也很簡單,因為domain object是映射數據庫字段的,數據庫字段不會頻繁變動,所以domain object也相對穩定,而面向數據庫持久化編程的DAO層也不過就是CRUD而已,不會有更多的花樣,所以也很穩定。

          問題就在于這個充當business workflow facade的業務邏輯對象,它的變動是相當頻繁的。業務邏輯對象通常都是無狀態的、受事務控制的、Singleton類,我們可以考察一下業務邏輯對象都有哪幾類業務邏輯方法:

          第一類:DAO接口方法的代理,就是上面例子中的loadItemById方法和findAll方法。

          ItemManager之所以要代理這種類,目的有兩個:向Web層提供統一的服務調用入口點和給持久化方法增加事務控制功能。這兩點都很容易理解,你不能既給Web層程序員提供xxxManager,也給他提供xxxDao,所以你需要用xxxManager封裝xxxDao,在這里,充當了一個簡單代理功能;而事務控制也是持久化方法必須的,事務可能需要跨越多個DAO方法調用,所以必須放在業務邏輯層,而不能放在DAO層。

          但是必須看到,對于一個典型的web應用來說,絕大多數的業務邏輯都是簡單的CRUD邏輯,所以這種情況下,針對每個DAO方法,xxxManager都需要提供一個對應的封裝方法,這不但是非常枯燥的,也是令人感覺非常不好的。

          第二類:domain logic的方法代理。就是上面例子中placeBid方法。雖然Item已經有了placeBid方法,但是ItemManager仍然需要封裝一下Item的placeBid,然后再提供一個簡單封裝之后的代理方法。

          這和第一種情況類似,其原因也一樣,也是為了給Web層提供一個統一的服務調用入口點和給隱式的持久化動作提供事務控制。

          同樣,和第一種情況一樣,針對每個domain logic方法,xxxManager都需要提供一個對應的封裝方法,同樣是枯燥的,令人不爽的。

          第三類:需要多個domain object和DAO參與協作的business workflow。這種情況是業務邏輯對象真正應該完成的職責。

          在這個簡單的例子中,沒有涉及到這種情況,不過大家都可以想像的出來這種應用場景,因此不必舉例說明了。

          通過上面的分析可以看出,只有第三類業務邏輯方法才是業務邏輯對象真正應該承擔的職責,而前兩類業務邏輯方法都是“無奈之舉”,不得不為之的事情,不但枯燥,而且令人沮喪。

          分析完了業務邏輯對象,我們再回頭看一下domain object,我們要仔細考察一下domain logic的話,會發現domain logic也分為兩類:

          第一類:需要持久層框架隱式的實現透明持久化的domain logic,例如Item的placeBid方法中的這一句:

          代碼
          						this
          						.
          						getBids
          						().
          						add
          						(
          						newBid
          						);
          				

          上面已經著重提到,雖然這僅僅只是一個Java集合的添加新元素的操作,但是實際上通過事務的控制,會潛在的觸發兩條SQL:一條是insert一條記錄到bid表,一條是更新item表相應的記錄。如果我們讓Item脫離Hibernate進行單元測試,它就是一個單純的Java集合操作,如果我們把他加入到Hibernate框架中,他就會潛在的觸發兩條SQL,這就是隱式的依賴于持久化的domain logic
          特別請注意的一點是:在沒有Hibernate/JDO這類可以實現“透明的持久化”工具出現之前,這類domain logic是無法實現的。

          對于這一類domain logic,業務邏輯對象必須提供相應的封裝方法,以實現事務控制。

          第二類:完全不依賴持久化的domain logic,例如readonly例子中的Topic,如下:

          java代碼
          class Topic{
          booleanisAllowReply(){
          CalendardueDate=Calendar.getInstance();
          dueDate.setTime(lastUpdatedTime);
          dueDate.add(Calendar.DATE,forum.timeToLive);

          Datenow=newDate();
          returnnow.after(dueDate.getTime());
          }
          }

          注意這個isAllowReply方法,他和持久化完全不發生一丁點關系。在實際的開發中,我們同樣會遇到很多這種不需要持久化的業務邏輯(主要發生在日期運算、數值運算和枚舉運算方面),這種domain logic不管脫離不脫離所在的框架,它的行為都是一致的。對于這種domain logic,業務邏輯層并不需要提供封裝方法,它可以適用于任何場合。

          posted on 2006-10-19 10:01 水煮三國 閱讀(501) 評論(0)  編輯  收藏 所屬分類: J2EE 、Hibernate
          <2006年10月>
          24252627282930
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          常用鏈接

          留言簿(4)

          隨筆分類(85)

          隨筆檔案(89)

          文章分類(14)

          文章檔案(42)

          收藏夾(37)

          java

          oracle

          Sybase

          搜索

          •  

          積分與排名

          • 積分 - 210989
          • 排名 - 266

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 大洼县| 东明县| 休宁县| 晋中市| 义马市| 鹤山市| 麻江县| 航空| 大厂| 图木舒克市| 平舆县| 锡林郭勒盟| 宁阳县| 黔东| 丁青县| 咸宁市| 页游| 烟台市| 当雄县| 苏尼特左旗| 正蓝旗| 谷城县| 靖边县| 三都| 林甸县| 新安县| 鲁甸县| 隆尧县| 清流县| 图片| 屏东县| 古浪县| 台南市| 云林县| 嘉义县| 临澧县| 广饶县| 鹿泉市| 丽江市| 福州市| 唐海县|