老妖的博客
          現(xiàn)實的中沒有幾個人能夠真為對方去死,甚至山盟海誓很快就會在金錢面前變的微不足道,這才是生活。沒有永遠的愛,除了你的父母對你,當然也就沒有永遠的恨,更沒有永遠的痛,時間是最好的治療大師,它會很快撫平你心靈上累累的傷痕。很多年以后你想起來時,那些在你生命中洶涌來往的人群至多是個模糊的影子或者毫無意義的名字
          posts - 105,  comments - 171,  trackbacks - 0
          1public interface CompositeAct extends Act 
          2
          3Act[] getActs(); 
          4}
           
          一直想系統(tǒng)的整理一下自己有關(guān)Domain Model實踐的嘗試。但總覺得自己的想法還不夠系統(tǒng)而作罷。
          然而從另一方面看“系統(tǒng)的東西”也許永遠做不到,失去了目標的生活該會多乏味。
          因此我決定將自己有關(guān)Domain Model設(shè)計的有關(guān)實踐和思考和盤托出,也算是拋磚引玉。歡迎大家
          參與討論,遇到同你的觀點相左的地方,希望能以包容的態(tài)度來面對,我們是朝同一方向走的伙伴而不是
          相互對視的敵人。:)

          在深入討論之前我先拋出一些原則和概念,最后你會看到這些概念和原則的威力。
          1.按照概念依賴的原則來組織業(yè)務(wù)層。
          2.將業(yè)務(wù)活動(業(yè)務(wù)流程)建模成類。
          3.用業(yè)務(wù)活動(業(yè)務(wù)流程)作為關(guān)聯(lián)整個業(yè)務(wù)層各種對象的骨架。
          4.在業(yè)務(wù)活動中鑿出擴展點,使用不同接口分離不同性質(zhì)業(yè)務(wù)對象。
          5.將對象的存儲理解為業(yè)務(wù)層概念。
          ......

          概念依賴

          這是我認為能否得到良好業(yè)務(wù)層最重要的概念。
          在我系統(tǒng)框架設(shè)計將要完成,開始涉及業(yè)務(wù)層設(shè)計時,我腦袋一片空白,書上,大家討論的大多是整個系統(tǒng)的結(jié)構(gòu)從UI層
          到服務(wù)層到數(shù)據(jù)訪問層到數(shù)據(jù)庫。到底業(yè)務(wù)層該如何組織?Martin Fowler的POEAA的書中沒有回答。找到的相關(guān)
          書籍也都過于空泛。Martin Fowler的分析模式有些用處,但不夠系統(tǒng)。透過Martin fowler網(wǎng)站,我拿到了
          Domain Driven Design的發(fā)行前版本。該書給了我很大的啟示。其中的要點有:
          關(guān)于關(guān)聯(lián):
          1.Imposing a traversal direction (強制一個關(guān)聯(lián)的導航方向)
          ......
          關(guān)于Responsibility Layers(業(yè)務(wù)職責層)的劃分:
          作者給出了三個指導原則:Conceptual dependency.(概念依賴)為其中一項。
          書中給出的描述的是業(yè)務(wù)職責層上層的對象需要通過下層對象才能在概念上完整,
          相反下層對象則可獨立于上層對象存在含義。這樣天然的下層對象相對于上層對象
          會更穩(wěn)定。并且在今后演變的過程中,使同擴展的方式來完善系統(tǒng),而不是改變對象
          的方式。
          通過實踐,我覺得這條原則可以應(yīng)用在任何兩個有關(guān)聯(lián)的業(yè)務(wù)對象上。通常可以通過
          概念依賴先建立一個導航方向。這能夠滿足大多數(shù)的需求。當確實需要反向?qū)Ш綍r,
          只要理由充分可以隨時加上,并且如果先前將這兩個對象放入不同包中,這時需要
          將他們合并到同一個包中。
          我見過一個不好的設(shè)計。Customer具有很多Flag分別標記該客戶是否掛失,凍結(jié),注銷等等。
          通常叫做客戶狀態(tài),然而這是不對的,這違背了單一職責原則。事實上除了注銷外
          掛失和凍結(jié)都不應(yīng)該算作Customer的本質(zhì)屬性。相反我把他們看作某種約束,進而把掛失看作
          一種協(xié)議.....因為Customer的概念可以不依賴于掛失和凍結(jié)的概念,相反掛失和凍結(jié)卻要依賴
          Customer的概念,應(yīng)為這是他們動作的主體。
          同樣的一開始就讓Customer有GetAccount的方法同樣不好。因為Customer的概念確實不依賴Account
          XXXAccount卻可以有Customer的屬性,Account在概念上依賴Customer。
          按照概念依賴原則我們能更好的理解業(yè)務(wù)職責層的劃分。DDD中建議了如下的職責層。
          按從高到低分別為:

          依賴方向
          | Decision
          | Policy
          | Commitment
          | Operation
          V Potential

          Potential中包括類似Customer,Employee等Party方面的類。對應(yīng)支持業(yè)務(wù)。
          Operation中包括了核心業(yè)務(wù)如存取款,買賣以及同這些業(yè)務(wù)關(guān)聯(lián)的Account,Product等等。
          Commmitment對于客戶包括同客戶簽訂的協(xié)議等。對于員工來說包括授權(quán)等。
          Policy包括計算某種收費的策略,比如電信收費的算法。對應(yīng)支持業(yè)務(wù)。
          Decision包括主要對應(yīng)于管理業(yè)務(wù)。監(jiān)控系統(tǒng)多在這層。
          從上到下觀察,很好的遵循了概念依賴的原則。
          從另一方面來看,可以根據(jù)概念隨著時間發(fā)展的順序來建立對象之間的關(guān)系。這樣會天然的滿足概念依賴原則。
          后面發(fā)展起來的概念可以依賴前面的已經(jīng)存在的概念,而反過來這不可。這是系統(tǒng)穩(wěn)定的關(guān)鍵。
          同客戶簽訂的各種協(xié)議可以不斷的發(fā)展,但是客戶對象是穩(wěn)定的。
          同理收費的策略可以變化但是最終反映到帳戶上的都只是對Balance的變更。所以收費策略比
          帳戶更不穩(wěn)定。
          客戶對象也要比帳戶對象穩(wěn)定。

          從按照穩(wěn)定的方向依賴的原則出發(fā),我們可以得到對象間的單向依賴。當然也會存在雙向關(guān)聯(lián)
          的對象,然而這種情況在我的實踐中不是很多。而且一旦你懂得了單向關(guān)聯(lián)的好處后,你就會
          謹慎的使用雙向關(guān)聯(lián)。濫用關(guān)聯(lián)會使得整個業(yè)務(wù)層象DDD中說的,變成一大塊“果凍”,你隨便觸動
          果凍某一塊,整個果凍都會顫動。
          同樣為了簡化設(shè)計,對象的關(guān)系中多對多的關(guān)系盡量避免。如果可以
          則通過限定角色轉(zhuǎn)化為一對多或一對一的關(guān)系。
          以上是關(guān)于概念依賴的觀念,下面讓我們看看如何建模業(yè)務(wù)中的活動。
          有一種做法是使用分析模型中的控制類直接映射到設(shè)計中類中。我看來這不是好的做法。
          這里談?wù)劮治雠c設(shè)計的區(qū)別。
          從分析的角度來看,業(yè)務(wù)實體總是被動的。業(yè)務(wù)是通過控制對象操作業(yè)務(wù)實體來完成的。
          分析時我們是關(guān)注是什么問題。這要求我們客觀的來描述現(xiàn)實。
          進入設(shè)計階段我們關(guān)注的是如何解決的問題。控制對象施加與業(yè)務(wù)實體的操作加入不涉及
          第三者,則這個操作可以并入被操作的實體類中。然而分析中控制對象的概念是如此的
          深刻,以至于只涉及Customer的ChangePassword方法該放到哪里都成了問題。類不是
          “某概念 + 所關(guān)心該概念的屬性 + 最終施加與這些屬性上的操作” 的封裝,又是什么呢?
          下面的問題是如何建模跨越多個業(yè)務(wù)實體的操作?
          舉個例子:銀行開戶。
          現(xiàn)在假設(shè)開戶時涉及到下面的一些操作對象。
          創(chuàng)建一個Customer對象。
          創(chuàng)建一個CapitalAccount對象。
          存入一定數(shù)額的現(xiàn)金。
          記錄一筆開戶流水。
          整個業(yè)務(wù)活動,我可以建模為OpenCustomerAct對象。偽碼如下:
          public class OpenCustomerAct extends CustomerAct 

           
          public void override doRun() 

          Customer customer 
          = Customer.create(); 
          CapitalAccount capitalAccount 
          = CapitalAccount.create(customer,); 
          capitalAccount.deposit(); 
          OpenCustomerLog.create(
          this); 
          }
           
           
          }
           

          所需的參數(shù)通過構(gòu)造函數(shù)得到。
          將所有的業(yè)務(wù)活動都建模成一個Act,這非常重要。甚至你可以在Session中放入一個Act來
          表示當前正在進行的業(yè)務(wù)。所有的擴展都是從Act開始的。
          假如你要對Act施加某種檢查,那么對doRun方法進行攔截可以達到該目的。
          用例能夠簡化到只剩下流程,同樣道理Act也可以做到這點。
          對于象RichClient的交互模式,通常只在最后才提交業(yè)務(wù),中間的交互都是在準備提交的數(shù)據(jù)。
          那么在中間調(diào)用的方法中可以只new XXXAct而不執(zhí)行doRun操作。這樣做是因為中間的調(diào)用
          可能會用到XXXAct來作為上下文。現(xiàn)在我還沒有想好在這樣的中間過程中,如何能夠觸發(fā)
          植入到donRun前的檢查?或許可以創(chuàng)建一個空doRun的子類覆蓋掉父類實際的操作?
          Act
          1public interface Act 
          2
          3Operator getOperator();//誰 
          4Date getOccurDate();//在什么時間 
          5String getOccurPlace();//什么地點 
          6BusinessType getBusinessType();//做什么業(yè)務(wù) 
          7ActState getActState();//業(yè)務(wù)運行的當前狀態(tài) 
          8}
           
          9

          “誰在什么時間什么地點做了什么業(yè)務(wù)。”
          這描述了任何業(yè)務(wù)的基本方面。從哲學的角度來看,“我們得到了Act,我們就得到了事物的基礎(chǔ)”。
          當我們具體的描述某項業(yè)務(wù)時,假如需要向調(diào)用方暴露特定的屬性。
          我們可以隨時添加到Act的子接口中。
          例如同Customer相關(guān)的Act可定義為:

           

          1public interface CustomerAct extends Act 
          2
          3Cutomer getCustomer();//針對哪個客戶 
          4}
           
          在復雜一點的情況下,如業(yè)務(wù)需要多人協(xié)作完成,可以通過組合模式達到目的。
          涉及到一段時間有中間狀態(tài)的工作流也應(yīng)該可以作為Act的子接口進行擴展。
          不過我沒有做過這方面的嘗試。

          將Act放入Session

          將Act放入Session使得可以方便得到業(yè)務(wù)運行的上下文。而且通過擴展Act。
          可以從Act或其子接口中得到想得到的任何東西,這使得任何擴展都成為可能。

          這里說明一下Act類的位置應(yīng)當放入Potential層中,并且與Operator在一起。
          因為Potential層的業(yè)務(wù)對象也需要業(yè)務(wù)活動來維護。
          如果你的框架中Sesion在更基礎(chǔ)的包中,則可以給Act提供一個空內(nèi)容的父接口,放入Session所在的包中。
           1public interface AbstractAct 
           2
           3}
           
           4
           5public interface Act extends AbstractAct 
           6
           7 
           8}
           
           9Session提供得到AbstractAct的入口。 
          10public class Session 
          11
          12 
          13static public AbstractAct getAbstractAct() 
          14
          15return Instance().abstractAct; 
          16}
           
          17 
          18}
           
          posted on 2005-09-29 00:35 老妖 閱讀(540) 評論(1)  編輯  收藏

          FeedBack:
          # re: Domain Model 探索(一)--摘自:javaeye
          2013-08-14 10:03 | GoDaddy域名
          博主的文章技術(shù)性都那么強啊  回復  更多評論
            

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


          網(wǎng)站導航:
           

          <2005年9月>
          28293031123
          45678910
          11121314151617
          18192021222324
          2526272829301
          2345678

          常用鏈接

          隨筆分類(48)

          隨筆檔案(104)

          好友鏈接

          我的豆瓣

          積分與排名

          • 積分 - 221811
          • 排名 - 257

          最新評論

          閱讀排行榜

          主站蜘蛛池模板: 黄梅县| 丘北县| 青冈县| 南通市| 南涧| 类乌齐县| 永吉县| 苍梧县| 海淀区| 原平市| 扎兰屯市| 安达市| 宁波市| 房山区| 福海县| 宜州市| 莱阳市| 柳林县| 历史| 崇阳县| 虎林市| 壤塘县| 甘南县| 西宁市| 文成县| 白朗县| 阿荣旗| 延津县| 贺兰县| 赣榆县| 井冈山市| 勐海县| 内丘县| 郧西县| 壤塘县| 怀宁县| 上杭县| 安吉县| 海安县| 杨浦区| 永济市|