原文:http://www.javaeye.com/topic/17579
關(guān)于領(lǐng)域模型的設(shè)計問題,JavaEye已經(jīng)組織過n多次大規(guī)模討論,幾乎每過一段時期就會出現(xiàn)一次。最近出現(xiàn)了一個新的趨勢,Craig Walls在自己的blog上面寫一篇文章,介紹如何使用Spring2.0和AspectJ的新特性給domain object注入DAO依賴,即如何實現(xiàn)post-instantiation,請見:
http://jroller.com/page/habuma?entry=spring_2_0_vs_the
與此同時,ajoo也給出了nuts的post-instantiation方案,請見:
http://www.javaeye.com/display/ajoo/Dependency+Injection+For+Rich+Domain+Model
因此,從技術(shù)手段來上說,對于Spring/Hibernate架構(gòu),Martin的Rich domin model變得可行了,那么讓我們看看究竟有哪些領(lǐng)域模型,以及他們的優(yōu)缺點:
一、失血模型
失血模型請看
http://forum.javaeye.com/viewtopic.php?t=11712
中列舉的第一種模型,簡單來說,就是domain object只有屬性的getter/setter方法,沒有任何業(yè)務(wù)邏輯。
二、貧血模型
貧血模型請看
http://forum.javaeye.com/viewtopic.php?t=11712
中列舉的第二種模型,簡單來說,就是domain ojbect包含了不依賴于持久化的領(lǐng)域邏輯,而那些依賴持久化的領(lǐng)域邏輯被分離到Service層。
Service(業(yè)務(wù)邏輯,事務(wù)封裝) --> DAO ---> domain object
這種模型的優(yōu)點:
1、各層單向依賴,結(jié)構(gòu)清楚,易于實現(xiàn)和維護
2、設(shè)計簡單易行,底層模型非常穩(wěn)定
這種模型的缺點:
1、domain object的部分比較緊密依賴的持久化domain logic被分離到Service層,顯得不夠OO
2、Service層過于厚重
三、充血模型
充血模型和第二種模型差不多,所不同的就是如何劃分業(yè)務(wù)邏輯,即認為,絕大多業(yè)務(wù)邏輯都應(yīng)該被放在domain object里面(包括持久化邏輯),而Service層應(yīng)該是很薄的一層,僅僅封裝事務(wù)和少量邏輯,不和DAO層打交道。
Service(事務(wù)封裝) ---> domain object <---> DAO
這種模型的優(yōu)點:
1、更加符合OO的原則
2、Service層很薄,只充當(dāng)Facade的角色,不和DAO打交道。
這種模型的缺點:
1、DAO和domain object形成了雙向依賴,復(fù)雜的雙向依賴會導(dǎo)致很多潛在的問題。
2、如何劃分Service層邏輯和domain層邏輯是非常含混的,在實際項目中,由于設(shè)計和開發(fā)人員的水平差異,可能導(dǎo)致整個結(jié)構(gòu)的混亂無序。
3、考慮到Service層的事務(wù)封裝特性,Service層必須對所有的domain object的邏輯提供相應(yīng)的事務(wù)封裝方法,其結(jié)果就是Service完全重定義一遍所有的domain logic,非常煩瑣,而且Service的事務(wù)化封裝其意義就等于把OO的domain logic轉(zhuǎn)換為過程的Service TransactionScript。該充血模型辛辛苦苦在domain層實現(xiàn)的OO在Service層又變成了過程式,對于Web層程序員的角度來看,和貧血模型沒有什么區(qū)別了。
四、脹血模型
基于充血模型的第三個缺點,有同學(xué)提出,干脆取消Service層,只剩下domain object和DAO兩層,在domain object的domain logic上面封裝事務(wù)。
domain object(事務(wù)封裝,業(yè)務(wù)邏輯) <---> DAO
似乎ruby on rails就是這種模型,他甚至把domain object和DAO都合并了。
該模型優(yōu)點:
1、簡化了分層
2、也算符合OO
該模型缺點:
1、很多不是domain logic的service邏輯也被強行放入domain object ,引起了domain ojbect模型的不穩(wěn)定
2、domain object暴露給web層過多的信息,可能引起意想不到的副作用。
在這四種模型當(dāng)中,失血模型和脹血模型應(yīng)該是不被提倡的。而貧血模型和充血模型從技術(shù)上來說,都已經(jīng)是可行的了。但是我個人仍然主張使用貧血模型。其理由:
1、參考充血模型第三個缺點,由于暴露給web層程序拿到的還是Service Transaction Script,對于web層程序員來說,底層OO意義喪失了。
2、參考充血模型第三個缺點,為了事務(wù)封裝,Service層要給每個domain logic提供一個過程化封裝,這對于編程來說,做了多余的工作,非常煩瑣。
3、domain object和DAO的雙向依賴在做大項目中,考慮到團隊成員的水平差異,很容易引入不可預(yù)知的潛在bug。
4、如何劃分domain logic和service logic的標(biāo)準(zhǔn)是不確定的,往往要根據(jù)個人經(jīng)驗,有些人就是覺得某個業(yè)務(wù)他更加貼近domain,也有人認為這個業(yè)務(wù)是貼近service的。由于劃分標(biāo)準(zhǔn)的不確定性,帶來的后果就是實際項目中會產(chǎn)生很多這樣的爭議和糾紛,不同的人會有不同的劃分方法,最后就會造成整個項目的邏輯分層混亂。這不像貧血模型中我提出的按照是否依賴持久化進行劃分,這種標(biāo)準(zhǔn)是非常確定的,不會引起爭議,因此團隊開發(fā)中,不會產(chǎn)生此類問題。
5、貧血模型的domain object確實不夠rich,但是我們是做項目,不是做研究,好用就行了,管它是不是那么純的OO呢?其實我不同意firebody認為的貧血模型在設(shè)計模型和實現(xiàn)代碼中有很大跨越的說法。一個設(shè)計模型到實現(xiàn)的時候,你直接得到兩個類:一個實體類,一個控制類就行了,沒有什么跨越。
關(guān)于領(lǐng)域模型的問題,限于時間原因,暫時不能展開詳談,待有空,寫篇更加詳細的文章。
關(guān)于領(lǐng)域模型的設(shè)計問題,JavaEye已經(jīng)組織過n多次大規(guī)模討論,幾乎每過一段時期就會出現(xiàn)一次。最近出現(xiàn)了一個新的趨勢,Craig Walls在自己的blog上面寫一篇文章,介紹如何使用Spring2.0和AspectJ的新特性給domain object注入DAO依賴,即如何實現(xiàn)post-instantiation,請見:
http://jroller.com/page/habuma?entry=spring_2_0_vs_the
與此同時,ajoo也給出了nuts的post-instantiation方案,請見:
http://www.javaeye.com/display/ajoo/Dependency+Injection+For+Rich+Domain+Model
因此,從技術(shù)手段來上說,對于Spring/Hibernate架構(gòu),Martin的Rich domin model變得可行了,那么讓我們看看究竟有哪些領(lǐng)域模型,以及他們的優(yōu)缺點:
一、失血模型
失血模型請看
http://forum.javaeye.com/viewtopic.php?t=11712
中列舉的第一種模型,簡單來說,就是domain object只有屬性的getter/setter方法,沒有任何業(yè)務(wù)邏輯。
二、貧血模型
貧血模型請看
http://forum.javaeye.com/viewtopic.php?t=11712
中列舉的第二種模型,簡單來說,就是domain ojbect包含了不依賴于持久化的領(lǐng)域邏輯,而那些依賴持久化的領(lǐng)域邏輯被分離到Service層。
Service(業(yè)務(wù)邏輯,事務(wù)封裝) --> DAO ---> domain object
這種模型的優(yōu)點:
1、各層單向依賴,結(jié)構(gòu)清楚,易于實現(xiàn)和維護
2、設(shè)計簡單易行,底層模型非常穩(wěn)定
這種模型的缺點:
1、domain object的部分比較緊密依賴的持久化domain logic被分離到Service層,顯得不夠OO
2、Service層過于厚重
三、充血模型
充血模型和第二種模型差不多,所不同的就是如何劃分業(yè)務(wù)邏輯,即認為,絕大多業(yè)務(wù)邏輯都應(yīng)該被放在domain object里面(包括持久化邏輯),而Service層應(yīng)該是很薄的一層,僅僅封裝事務(wù)和少量邏輯,不和DAO層打交道。
Service(事務(wù)封裝) ---> domain object <---> DAO
這種模型的優(yōu)點:
1、更加符合OO的原則
2、Service層很薄,只充當(dāng)Facade的角色,不和DAO打交道。
這種模型的缺點:
1、DAO和domain object形成了雙向依賴,復(fù)雜的雙向依賴會導(dǎo)致很多潛在的問題。
2、如何劃分Service層邏輯和domain層邏輯是非常含混的,在實際項目中,由于設(shè)計和開發(fā)人員的水平差異,可能導(dǎo)致整個結(jié)構(gòu)的混亂無序。
3、考慮到Service層的事務(wù)封裝特性,Service層必須對所有的domain object的邏輯提供相應(yīng)的事務(wù)封裝方法,其結(jié)果就是Service完全重定義一遍所有的domain logic,非常煩瑣,而且Service的事務(wù)化封裝其意義就等于把OO的domain logic轉(zhuǎn)換為過程的Service TransactionScript。該充血模型辛辛苦苦在domain層實現(xiàn)的OO在Service層又變成了過程式,對于Web層程序員的角度來看,和貧血模型沒有什么區(qū)別了。
四、脹血模型
基于充血模型的第三個缺點,有同學(xué)提出,干脆取消Service層,只剩下domain object和DAO兩層,在domain object的domain logic上面封裝事務(wù)。
domain object(事務(wù)封裝,業(yè)務(wù)邏輯) <---> DAO
似乎ruby on rails就是這種模型,他甚至把domain object和DAO都合并了。
該模型優(yōu)點:
1、簡化了分層
2、也算符合OO
該模型缺點:
1、很多不是domain logic的service邏輯也被強行放入domain object ,引起了domain ojbect模型的不穩(wěn)定
2、domain object暴露給web層過多的信息,可能引起意想不到的副作用。
在這四種模型當(dāng)中,失血模型和脹血模型應(yīng)該是不被提倡的。而貧血模型和充血模型從技術(shù)上來說,都已經(jīng)是可行的了。但是我個人仍然主張使用貧血模型。其理由:
1、參考充血模型第三個缺點,由于暴露給web層程序拿到的還是Service Transaction Script,對于web層程序員來說,底層OO意義喪失了。
2、參考充血模型第三個缺點,為了事務(wù)封裝,Service層要給每個domain logic提供一個過程化封裝,這對于編程來說,做了多余的工作,非常煩瑣。
3、domain object和DAO的雙向依賴在做大項目中,考慮到團隊成員的水平差異,很容易引入不可預(yù)知的潛在bug。
4、如何劃分domain logic和service logic的標(biāo)準(zhǔn)是不確定的,往往要根據(jù)個人經(jīng)驗,有些人就是覺得某個業(yè)務(wù)他更加貼近domain,也有人認為這個業(yè)務(wù)是貼近service的。由于劃分標(biāo)準(zhǔn)的不確定性,帶來的后果就是實際項目中會產(chǎn)生很多這樣的爭議和糾紛,不同的人會有不同的劃分方法,最后就會造成整個項目的邏輯分層混亂。這不像貧血模型中我提出的按照是否依賴持久化進行劃分,這種標(biāo)準(zhǔn)是非常確定的,不會引起爭議,因此團隊開發(fā)中,不會產(chǎn)生此類問題。
5、貧血模型的domain object確實不夠rich,但是我們是做項目,不是做研究,好用就行了,管它是不是那么純的OO呢?其實我不同意firebody認為的貧血模型在設(shè)計模型和實現(xiàn)代碼中有很大跨越的說法。一個設(shè)計模型到實現(xiàn)的時候,你直接得到兩個類:一個實體類,一個控制類就行了,沒有什么跨越。
關(guān)于領(lǐng)域模型的問題,限于時間原因,暫時不能展開詳談,待有空,寫篇更加詳細的文章。