<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Johnny's Collections

    生活總是有太多的無(wú)奈與失望,讓我們以在努力學(xué)習(xí)和工作中獲得的成就感和快樂(lè)來(lái)沖淡它們。

    BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
      10 Posts :: 0 Stories :: 80 Comments :: 0 Trackbacks

    領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力

     

           曾經(jīng)參與過(guò)系統(tǒng)維護(hù)或是在現(xiàn)有系統(tǒng)中進(jìn)行迭代開(kāi)發(fā)的軟件工程師們,你們是否有過(guò)這樣的痛苦經(jīng)歷:當(dāng)需要修改一個(gè)Bug的時(shí)候,面對(duì)一個(gè)類(lèi)中成百上千行的代碼,沒(méi)有注釋?zhuān)姘俟值姆椒ê妥兞棵郑瑢訉忧短椎姆椒ㄕ{(diào)用,混亂不堪的結(jié)構(gòu),不要說(shuō)準(zhǔn)確找到Bug所在的位置,就是要清晰知道一段代碼究竟是做了什么也非常困難,最終,改對(duì)了一個(gè)Bug,卻多冒出N個(gè)新Bug;同樣的情況,當(dāng)你拿到一份新的需求,需要在現(xiàn)有系統(tǒng)中添加功能的時(shí)候,面對(duì)一行行完全過(guò)程式的代碼,需要使用一個(gè)功能時(shí),不知道是應(yīng)該自己編寫(xiě),還是應(yīng)該尋找是否已經(jīng)存在的方法,編寫(xiě)一個(gè)非常簡(jiǎn)單的新、刪、改功能,卻要費(fèi)盡九牛二虎之力,最終發(fā)現(xiàn),系統(tǒng)存在著太多的重復(fù)邏輯,閱讀、測(cè)試、修改非常困難。在經(jīng)歷了這些痛苦之后,你們是否會(huì)不約而同的發(fā)出一個(gè)感慨:與其進(jìn)行系統(tǒng)維護(hù)和迭代開(kāi)發(fā),還不如重新設(shè)計(jì)開(kāi)發(fā)一個(gè)新的系統(tǒng)來(lái)得痛快?

           面對(duì)這一系列讓軟件嵌入無(wú)底泥潭的問(wèn)題,基于面向?qū)ο笏枷氲念I(lǐng)域驅(qū)動(dòng)設(shè)計(jì)方法是一個(gè)很好的解決方法。從事過(guò)系統(tǒng)設(shè)計(jì)的富有經(jīng)驗(yàn)的設(shè)計(jì)師們,對(duì)職責(zé)單一原則、信息專(zhuān)家、充血/貧血模型、模型驅(qū)動(dòng)設(shè)計(jì)這些名詞或概念應(yīng)該不會(huì)感到陌生。面向?qū)ο蟮脑O(shè)計(jì)大師Martin Fowler不止一次的在他的Blog和著作《企業(yè)應(yīng)用架構(gòu)模式》中倡導(dǎo)過(guò)上述概論在設(shè)計(jì)中的巨大威力,而另外一位領(lǐng)域模型的出色專(zhuān)家Eric Evans的著作《領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)》也為我們提供了不少寶貴的經(jīng)驗(yàn)和方法。

           筆者從事系統(tǒng)設(shè)計(jì)多年,將會(huì)在本系列文章中把本人對(duì)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的理解,結(jié)合工作過(guò)程中積累的實(shí)際項(xiàng)目經(jīng)驗(yàn)進(jìn)行淺析,希望與大家交流學(xué)習(xí)。

           在本系列博文的開(kāi)篇中,我將會(huì)拿出一個(gè)顯示的例子,先用傳統(tǒng)的面向過(guò)程方式,使用貧血模型進(jìn)行設(shè)計(jì),然后再逐步加入需求變更,讓讀者發(fā)現(xiàn),隨著系統(tǒng)的不斷變更,基于貧血模型的設(shè)計(jì)將會(huì)讓系統(tǒng)慢慢陷入泥潭,越來(lái)越難于維護(hù),然后再用基于面向?qū)ο蟮念I(lǐng)域驅(qū)動(dòng)設(shè)計(jì)重新上述過(guò)程,通過(guò)對(duì)比展示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)對(duì)于復(fù)雜的業(yè)務(wù)系統(tǒng)的威力。


           假設(shè)現(xiàn)在有一個(gè)銀行支付系統(tǒng)項(xiàng)目,其中的一個(gè)重要的業(yè)務(wù)用例是賬戶(hù)轉(zhuǎn)賬業(yè)務(wù)。系統(tǒng)使用迭代的方式進(jìn)行開(kāi)發(fā),在1.0版本中,該用例的功能需求非常簡(jiǎn)單,事件流描述如下:

    主事件流:

    1)  用戶(hù)登錄銀行的在線(xiàn)支付系統(tǒng)

    2)  選擇用戶(hù)在該銀行注冊(cè)的網(wǎng)上銀行賬戶(hù)

    3)  選擇需要轉(zhuǎn)賬的目標(biāo)賬戶(hù),輸入轉(zhuǎn)賬金額,申請(qǐng)轉(zhuǎn)賬

    4)  銀行系統(tǒng)檢查轉(zhuǎn)出賬戶(hù)的金額是否足夠

    5)  從轉(zhuǎn)出賬戶(hù)中扣除轉(zhuǎn)出金額(debit),更新轉(zhuǎn)出賬戶(hù)的余額

    6)  把轉(zhuǎn)出金額加入到轉(zhuǎn)入賬戶(hù)中(credit),更新轉(zhuǎn)入賬戶(hù)的余額

    備選事件流:

    4a)如果轉(zhuǎn)出賬戶(hù)中的余額不足,轉(zhuǎn)賬失敗,返回錯(cuò)誤信息

     

    面向過(guò)程的設(shè)計(jì)方式(貧血模型)

     

    設(shè)計(jì)方案如下(忽略展示層部分):

    1)  設(shè)計(jì)一個(gè)賬戶(hù)交易服務(wù)接口AccountingService,設(shè)計(jì)一個(gè)服務(wù)方法transfer(),并提供一個(gè)具體實(shí)現(xiàn)類(lèi)AccountingServiceImpl,所有賬戶(hù)交易業(yè)務(wù)的業(yè)務(wù)邏輯都置于該服務(wù)類(lèi)中。

    2)  提供一個(gè)AccountInfo和一個(gè)Account,前者是一個(gè)用于與展示層交換賬戶(hù)數(shù)據(jù)的賬戶(hù)數(shù)據(jù)傳輸對(duì)象,后者是一個(gè)賬戶(hù)實(shí)體(相當(dāng)于一個(gè)EntityBean),這兩個(gè)對(duì)象都是普通的JavaBean,具有相關(guān)屬性和簡(jiǎn)單的get/set方法。

     

    下面是AccountingServiceImpl.transfer()方法的實(shí)現(xiàn)邏輯(偽代碼):

     


    public class AccountingServiceImpl implements AccountingService {

           
    public void transfer(Long srcAccountId,Long destAccountId,BigDecimal amount) throws AccountingServiceException {

                  Account srcAccount 
    = accountRepository.getAccount(srcAccountId);

                  Account destAccount 
    = accountRepository.getAccount(destAccountId);

                  
    if(srcAccount.getBalance().compareTo(amount)<0)

                         
    throw new AccountingServiceException(AccountingService.BALANCE_IS_NOT_ENOUGH);

                  srcAccount.setBalance(srcAccount.getBalance().sbustract(amount));

                  destAccount.setBalance(destAccount.getBalance().add(amount));

           }

    }

     

    public class Account implements DomainObject {

           
    private Long id;

           
    private Bigdecimal balance;

          

    /**

     * getter/setter

     
    */

    }

     

           可以看到,由于1.0版本的功能需求非常簡(jiǎn)單,按面向過(guò)程的設(shè)計(jì)方式,把所有業(yè)務(wù)代碼置于AccountingServiceImpl中完全沒(méi)有問(wèn)題。

           這時(shí)候,新需求來(lái)了,在1.0.1版本中,需要為賬戶(hù)轉(zhuǎn)賬業(yè)務(wù)增加如下功能,在轉(zhuǎn)賬時(shí),首先需要判斷賬戶(hù)是否可用,然后,賬戶(hù)的余額還要分成兩部分:凍結(jié)部分和活躍部分,處于凍結(jié)部分的金額不能用于任何交易業(yè)務(wù),我們來(lái)看看變更后的代碼:

     


    public class AccountingServiceImpl implements AccountingService {

           
    public void transfer(Long srcAccountId,Long destAccountId,BigDecimal amount) throws AccountingServiceException {

                  Account srcAccount 
    = accountRepository.getAccount(srcAccountId);

                  Account destAccount 
    = accountRepository.getAccount(destAccountId);

                  
    if(!srcAccount.isActive() || !destAccount.isActive())

                         
    throw new AccountingServiceException(AccountingService.ACCOUNT_IS_NOT_AVAILABLE);

                  BigDecimal availableAmount 
    = srcAccount.getBalance().substract(srcAccount.getFrozenAmount());

                  
    if(availableAmount.compareTo(amount)<0)

                         
    throw new AccountingServiceException(AccountingService.BALANCE_IS_NOT_ENOUGH);

                  srcAccount.setBalance(srcAccount.getBalance().sbustract(amount));

                  destAccount.setBalance(destAccount.getBalance().add(amount));

           }

    }

     

    public class Account implements DomainObject {

           
    private Long id;

           
    private BigDecimal balance;

           
    private BigDecimal frozenAmount;

          

    /**

     * getter/setter

     
    */

    }

     

           可以看到,情況變得稍微復(fù)雜了,這時(shí)候,1.0.2的需求又來(lái)了,需要在每次交易成功后,創(chuàng)建一個(gè)交易明細(xì)賬,于是,我們又必須在transfer()方面里面增加創(chuàng)建并持久化交易明細(xì)賬的業(yè)務(wù)邏輯:

                 

         AccountTransactionDetails details= new AccountTransactionDetails(…);
         accountRepository.save(details);

          

           業(yè)務(wù)需求不斷復(fù)雜化:賬戶(hù)每筆轉(zhuǎn)賬的最大額度需要由其信用指數(shù)確定、需要根據(jù)銀行的手續(xù)費(fèi)策略計(jì)算并扣除一定的手續(xù)費(fèi)用……,隨著業(yè)務(wù)的復(fù)雜化,transfer()方法的邏輯變得越來(lái)越復(fù)雜,逐漸形成了上文所述的成百上千行代碼。有經(jīng)驗(yàn)的程序員可能會(huì)做出類(lèi)此“方法抽取”的重構(gòu),把轉(zhuǎn)賬業(yè)務(wù)按邏輯劃分成若干塊:判斷余額是否足夠、判斷賬戶(hù)的信用指數(shù)以確定每筆最大轉(zhuǎn)賬金額、根據(jù)銀行的手續(xù)費(fèi)策略計(jì)算手續(xù)費(fèi)、記錄交易明細(xì)賬……,從而使代碼更加結(jié)構(gòu)化。這是一個(gè)好的開(kāi)始,但還是顯然不足。

           假設(shè)某一天,系統(tǒng)需求增加一個(gè)新的模塊,為系統(tǒng)增加一個(gè)網(wǎng)上商城,讓銀行用戶(hù)可以進(jìn)行在線(xiàn)購(gòu)物,而在線(xiàn)購(gòu)物也存在著很多與賬戶(hù)貸記借記業(yè)務(wù)相同或相似的業(yè)務(wù)邏輯:判斷余額是否足夠、對(duì)賬戶(hù)進(jìn)行借貸操作(credit/debit)以改變余額、收取手續(xù)費(fèi)用、產(chǎn)生交易明細(xì)賬……

           面對(duì)這種情況,有兩種解決辦法:

    1)  AccountingServiceImpl中的相同邏輯拷貝到OnlineShoppingServiceImplementation

    2)  OnlineShoppingServiceImpl調(diào)用AccountingServiceImpl的相同服務(wù)

    顯然,第二種方法比第一種方法更好,結(jié)構(gòu)更清晰,維護(hù)更容易。但問(wèn)題在于,這樣就會(huì)形成網(wǎng)上商城服務(wù)模塊與賬戶(hù)收支服務(wù)模塊的不必要的依賴(lài)關(guān)系,系統(tǒng)的耦合度高了,如果系統(tǒng)為了更靈活的伸縮性,讓每個(gè)大業(yè)務(wù)模塊獨(dú)立進(jìn)行部署,還需要因?yàn)閮烧叩囊蕾?lài)關(guān)系建立分布式調(diào)用,這無(wú)疑增加了設(shè)計(jì)、開(kāi)發(fā)和運(yùn)維的成本。

    有經(jīng)驗(yàn)的設(shè)計(jì)人員可能會(huì)發(fā)現(xiàn)第三種解決辦法:把相同的業(yè)務(wù)邏輯抽取成一個(gè)新的服務(wù),作為公共服務(wù)同時(shí)供上述兩個(gè)業(yè)務(wù)模塊使用。這只是筆者將會(huì)馬上討論的方案——使用領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)。

     

     

     

    面向過(guò)程的領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)方式(充血模型)

     

           為了節(jié)省篇幅,這里就直接以最復(fù)雜的業(yè)務(wù)需求來(lái)進(jìn)行設(shè)計(jì)。

    領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的一個(gè)重要的概念是領(lǐng)域模型,首先,我們根據(jù)業(yè)務(wù)領(lǐng)域抽象出以下核心業(yè)務(wù)對(duì)象模型:


     

    Account:賬戶(hù),是整個(gè)系統(tǒng)的最核心的業(yè)務(wù)對(duì)象,它包括以下屬性:對(duì)象標(biāo)識(shí)、賬戶(hù)號(hào)、是否有效標(biāo)識(shí)、余額、凍結(jié)金額、賬戶(hù)交易明細(xì)集合、賬戶(hù)信用等級(jí)。

    AccountTransactionDetails:賬戶(hù)交易明細(xì),它從屬于賬戶(hù),每個(gè)賬戶(hù)有多個(gè)交易明細(xì),它包括以下屬性:對(duì)象標(biāo)識(shí)、所屬賬戶(hù)、交易類(lèi)型、交易發(fā)生金額、交易發(fā)生時(shí)間。

    AccountCreditDegree:賬戶(hù)信用等級(jí),它用于限制賬戶(hù)的每筆交易發(fā)生金額,包含以下屬性:對(duì)象標(biāo)識(shí)、對(duì)應(yīng)賬戶(hù)、信用指數(shù)。

    BankTransactionFeeCalculator:銀行交易手續(xù)費(fèi)用計(jì)算器,它包含一個(gè)常量:每筆交易的手續(xù)費(fèi)上限。

     

    我們知道,領(lǐng)域?qū)ο蟪司哂凶陨淼膶傩院蜖顟B(tài)之外,它的一個(gè)很重要的標(biāo)志是,它具有屬于自己職責(zé)范圍之內(nèi)的行為,這些行為封裝了其領(lǐng)域內(nèi)的領(lǐng)域業(yè)務(wù)邏輯。于是,我們進(jìn)行進(jìn)一步的建模,根據(jù)業(yè)務(wù)需求為領(lǐng)域?qū)ο笤O(shè)計(jì)業(yè)務(wù)方法:


     

    根據(jù)職責(zé)單一的原則,我們把功能需求中描述的功能合理的分配到不同的領(lǐng)域?qū)ο笾校?/span>

    Account

    • credit:向銀行賬戶(hù)存入金額,貸記
    • debit:從銀行賬戶(hù)劃出金額,借記
    • transferTo:把固定金額轉(zhuǎn)入指定賬戶(hù)
    • createTransactionDetails:創(chuàng)建交易明細(xì)賬
    • updateCreditIndex:更新賬戶(hù)的信用指數(shù)

    (我們可以看到,后兩個(gè)業(yè)務(wù)方法被聲明為protected,具體原因見(jiàn)后述)

     

    AccountCreditDegree

    • getMaxTransactionAmount:獲取所屬賬戶(hù)的每筆交易最大金額

     

    BankTransactionFeeCalculator

    • calculateTransactionFee:根據(jù)交易信息計(jì)算該筆交易的手續(xù)費(fèi)

     

    經(jīng)過(guò)這樣的設(shè)計(jì),前例中所有放置在服務(wù)對(duì)象的業(yè)務(wù)邏輯被分別劃入不同的負(fù)責(zé)相關(guān)職責(zé)的領(lǐng)域?qū)ο螽?dāng)中,下面的時(shí)序圖描述了AccountingServiceImpl的轉(zhuǎn)賬業(yè)務(wù)的實(shí)現(xiàn)邏輯(為了簡(jiǎn)化邏輯,我們忽略掉事物、持久化等邏輯):


     

    再看看AccountingServiceImpl.transfer()的實(shí)現(xiàn)邏輯:

     


    public class AccountingServiceImpl implements AccountingService {

           
    public void transfer(Long srcAccountId,Long destAccountId,BigDecimal amount) throws AccountDomainException {

                  Account srcAccount 
    = accountRepository.getAccount(srcAccountId);

                  Account destAccount 
    = accountRepository.getAccount(destAccountId);

                  srcAccount.transferTo(destAccount,amount);

           }

    }

     

    我們可以看到,上例那些復(fù)雜的業(yè)務(wù)邏輯:判斷余額是否足夠、判斷賬戶(hù)是否可用、改變賬戶(hù)余額、計(jì)算手續(xù)費(fèi)、判斷交易額度、產(chǎn)生交易明細(xì)賬……,都不再存在于AccountingServiceImplementationtransfer方法中,它們被委派給負(fù)責(zé)這些業(yè)務(wù)的領(lǐng)域?qū)ο蟮臉I(yè)務(wù)方法中去,現(xiàn)在應(yīng)該猜到為什么Account中有兩個(gè)方法被聲明為protected了吧,因?yàn)樗麄兪窃?/span>debitcredit方法被調(diào)用時(shí),由這兩個(gè)方法調(diào)用的,對(duì)于AccountingServiceImpl來(lái)說(shuō),由于產(chǎn)生交易明細(xì)(createTransactionDetails)和更新賬戶(hù)信用指數(shù)(updateCreditIndex)都不屬于其職責(zé)范圍,它不需要也無(wú)權(quán)使用這些邏輯。

     

    我們可以看到,使用領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)至少會(huì)帶來(lái)下述優(yōu)點(diǎn):

    • 業(yè)務(wù)邏輯被合理的分散到不同的領(lǐng)域?qū)ο笾校a結(jié)構(gòu)更加清晰,可讀性,可維護(hù)性更高。
    • 對(duì)象職責(zé)更加單一,內(nèi)聚度更高。
    • 復(fù)雜的業(yè)務(wù)模型可以通過(guò)領(lǐng)域建模(UML是一種主要方式)清晰的表達(dá),開(kāi)發(fā)人員甚至可以在不讀源碼的情況下就能了解業(yè)務(wù)和系統(tǒng)結(jié)構(gòu),這有利于對(duì)現(xiàn)存的系統(tǒng)進(jìn)行維護(hù)和迭代開(kāi)發(fā)。

     

    再看看如果這時(shí)需要加入網(wǎng)上商城的一個(gè)新的模塊,開(kāi)發(fā)人員需要怎么去做,還記得上面提過(guò)的第三種方案嗎?就是把賬戶(hù)貸記和借記的相關(guān)業(yè)務(wù)抽取到成一個(gè)公共服務(wù),同時(shí)供銀行在線(xiàn)支付系統(tǒng)和網(wǎng)上商城系統(tǒng)服務(wù),其實(shí)這個(gè)公共的服務(wù),本質(zhì)上就是這些具有領(lǐng)域邏輯的領(lǐng)域?qū)ο螅?/span>AccountAccountCreditDegree……,由此我們又可以發(fā)現(xiàn)領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的一大優(yōu)點(diǎn):

    • 系統(tǒng)高度模塊化,代碼重用度高,不會(huì)出現(xiàn)太多的重復(fù)邏輯。

     

    筆者經(jīng)驗(yàn)尚淺,而且文筆拙劣,希望通過(guò)這樣的一個(gè)場(chǎng)景的分析比較,能讓讀者初步認(rèn)識(shí)到基于面向?qū)ο蟮念I(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力,并在實(shí)際項(xiàng)目中嘗試應(yīng)用。本篇是領(lǐng)取驅(qū)動(dòng)設(shè)計(jì)系列博文的第一篇,在系列文章的第二篇博文中,筆者將會(huì)淺析VODTODOPO的概念、用處和區(qū)別,敬請(qǐng)各位對(duì)本系列博文感興趣的讀者關(guān)注并給予指導(dǎo)修正。

     

          

    posted on 2010-05-15 21:58 Johnny.Liang 閱讀(13352) 評(píng)論(20)  編輯  收藏 所屬分類(lèi): 系統(tǒng)設(shè)計(jì)

    Feedback

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-16 02:08 芒果網(wǎng)特價(jià)
    收藏了...期待下一篇  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-16 07:22 超級(jí)笨笨
    期待中.......  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-16 08:27 何楊
    UML圖是用什么工具畫(huà)的?  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-16 09:47 Johnny.Liang
    @何楊
    工具有很多,我用的是Enterprise Architecture試用版,還可以用Jude等。  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-17 17:54 蔣開(kāi)平
    收藏了,很不錯(cuò)...  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-19 01:45 hyde
    非常期待,加油  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力[未登錄](méi) 2010-05-21 09:06 Mike
    寫(xiě)得不錯(cuò),感謝分享!期待后續(xù)。  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-27 16:04 spell007
    樓主寫(xiě)的不錯(cuò),有點(diǎn)DDD的味道了,我先轉(zhuǎn)載,但是我有疑問(wèn),請(qǐng)問(wèn)srcAccount.transferTo(destAccount,amount)如何實(shí)現(xiàn),我要轉(zhuǎn)賬,那相關(guān)的數(shù)據(jù)肯定要保存在數(shù)據(jù)庫(kù)中的,莫非Account 對(duì)象里面要依賴(lài)DAO?那DAO又依賴(lài)Account,迷惑中~~  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-27 16:20 Johnny.Liang
    @spell007
    您好,這個(gè)問(wèn)題問(wèn)得非常好,我之前在應(yīng)用DDD做一個(gè)項(xiàng)目的時(shí)候,就跟項(xiàng)目成員做過(guò)討論,我們發(fā)現(xiàn),DO和Repository(即DAO,我習(xí)慣用非技術(shù)化命名來(lái)讓思維集中與業(yè)務(wù)而不是技術(shù))兩者是雙向依賴(lài)的。原因是:
    1)Repository必須依賴(lài)DO,因?yàn)樗繢O的數(shù)據(jù)結(jié)構(gòu),這無(wú)可厚非。
    2)為什么DO需要依賴(lài)于Repository呢?從實(shí)現(xiàn)角度來(lái)說(shuō),我的賬戶(hù)轉(zhuǎn)賬業(yè)務(wù)就可以看出這種依賴(lài)的存在,另外有些場(chǎng)景,比如有些領(lǐng)域業(yè)務(wù)邏輯需要查詢(xún)一些數(shù)據(jù),例如一個(gè)Order最多允許10個(gè)OrderItem,那么在order.addOrderItem的方法里面,就需要判斷當(dāng)前Order有多少個(gè)OrderItem,這就需要查詢(xún)(為了性能不全部加在OrderItem),從設(shè)計(jì)角度來(lái)看,我們想想,在計(jì)算機(jī)世界,由于DO在大部分情況下是必須持久化的,所以DO從功能上本身就對(duì)其Repository存在依賴(lài)關(guān)系,當(dāng)然,我們可以只依賴(lài)于接口,所以,基于 種種原因,我們不得不讓DO與Repository形成雙向依賴(lài)關(guān)系。

    這個(gè)問(wèn)題值得詳細(xì)討論,我會(huì)考慮在后面的系列博文增加一篇專(zhuān)門(mén)針對(duì)這個(gè)問(wèn)題進(jìn)行分析討論,非常感謝你提出這樣好的問(wèn)題。
      回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-05-28 09:20 虎嘯龍吟
    很好,很受用。博主可以寫(xiě)成書(shū)出版了  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-06-01 11:49 菠蘿大象
    關(guān)注這個(gè)系列,我也想研究下DDD開(kāi)發(fā),目前我所知道的,新版的Jdon框架是全面采用DDD技術(shù)做的,不過(guò)想看它的資料得付費(fèi),希望博主繼續(xù)努力,分享經(jīng)驗(yàn),一起討論。  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-06-03 11:11 Johnny.Liang
    @菠蘿大象
    Jdon框架采用DDD了么?沒(méi)有關(guān)注,不過(guò)個(gè)人覺(jué)得不解,DDD主要是針對(duì)企業(yè)應(yīng)用的,一個(gè)純技術(shù)框架,為什么要使用DDD。  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-06-25 15:25 Aidan
    我沒(méi)有發(fā)現(xiàn)你的PO,你的PO在哪?  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-06-26 20:51 Aidan
    您好,前面感謝你回答我的問(wèn)題,不知道有沒(méi)有機(jī)會(huì)與的詳細(xì)討論一下。我的QQ:501276913.期待,向前輩學(xué)習(xí),我只是一個(gè)小兵。  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-06-29 09:52 Johnny.Liang
    @Aidan
    聯(lián)系方式已經(jīng)發(fā)到你的郵箱,請(qǐng)查收  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2010-08-09 21:13 masterice
    您好,您的文我一直在關(guān)注,很有意思,有個(gè)小小的請(qǐng)求,您能不能把相對(duì)完整的代碼,發(fā)給我一份呢?只是想認(rèn)真學(xué)習(xí)。非常感謝您。
    ice_thunder@163.com  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力[未登錄](méi) 2010-09-23 11:58 kevin
    這個(gè)文章 我看到 只是將原先在serviceimpl的邏輯移動(dòng)到了account中, 假設(shè)將需求1.0.0到1.0.2在account#transferto方法中實(shí)現(xiàn)一遍 跟在serviceimpl面臨的改動(dòng)是一樣的 有啥好處 ?  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力[未登錄](méi) 2011-03-27 11:36 Simon
    對(duì)于只增刪改查的項(xiàng)目,領(lǐng)域建模感覺(jué)意義較小。  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2014-02-18 17:42 zuoca
    重要的是你的transferTo里是怎么實(shí)現(xiàn)的?這樣我很想看到  回復(fù)  更多評(píng)論
      

    # re: 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)系列文章(1)——通過(guò)現(xiàn)實(shí)例子顯示領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)的威力 2015-05-30 14:49 宋兵利
    這么好的文章,感謝了!  回復(fù)  更多評(píng)論
      

    主站蜘蛛池模板: 毛片视频免费观看| 免费a级毛片高清视频不卡| 污视频在线免费观看| 亚洲视频免费一区| 性色av免费观看| 亚洲国产人成精品| 亚洲VA中文字幕无码毛片| 在线免费观看亚洲| 亚洲国产精品自在自线观看| 三年片在线观看免费观看大全中国| a在线免费观看视频| 思思re热免费精品视频66 | 国产人成免费视频网站| 免费黄色小视频网站| 亚洲午夜福利717| 亚洲一区二区三区四区视频| 黄页网站在线视频免费| 久久久精品免费国产四虎| 最近2019中文字幕免费看最新| 久久久久亚洲精品男人的天堂| 亚洲精品第五页中文字幕| 老妇激情毛片免费| 91福利免费体验区观看区| 国产免费观看a大片的网站| 亚洲精品无码不卡在线播HE| 亚洲一区二区三区国产精华液| 一级一看免费完整版毛片| 亚洲成年人免费网站| 又粗又大又猛又爽免费视频| 亚洲AV日韩精品久久久久久| 亚洲成a人无码亚洲成av无码 | 久久精品熟女亚洲av麻豆| 久久免费动漫品精老司机| 国产乱子伦精品免费女| 亚洲影院在线观看| 国产午夜亚洲精品不卡免下载| 日韩免费人妻AV无码专区蜜桃| 国产亚洲精品免费| 久久亚洲美女精品国产精品| 十八禁的黄污污免费网站| 国产在线a免费观看|