Windows apache Android mysql 开源 nginx Firefox google Python 云计算 shell 微软 centos 编程 wordpress Ubuntu php 程序员 linux java

關於DDD領域驅動設計的理論知識收集匯總

最近一直在學習領域驅動設計(DDD)的理論知識,從網上搜集了一些個人認為比較有價值的東西,貼出來和大家分享一下:

我一直覺得不要盲目相信權威,比如不能一談起領域驅動設計,就一定認為國外的那個Eric Evans寫的那本書中的一些概念就一定是正確的,認為領域驅動設計就一定是聚合,聚合根,實體,值對象等概念。我們要有自己的思想,要有自己判斷真正的領域模型該是什麽樣子的勇氣和追求。

"領域驅動設計" = “問題域模型驅動領域建模” + “領域建模驅動軟件實現”
問題域建模的過程就是業務領域分析的過程,對於企業而言就是業務架構的分析和建立過程,這裏不包含任何OO的設計成分,主要從組織、流程和業務能力三個維度來分析業務。
記住很多模式沒有什麽用處,帶著問題在模式中尋找答案才是正確的使用方式,讓那種解決方案的思想融入到你的模型當中,然後徹底地忘掉那些所謂的模式名詞。
好的領域建模應該具有柔性,能夠伴隨著用戶一起成長。
這讓我意識到業務建模應該回歸自然:一談起來建模技術,就離不開國外提出的OO、EDA之類的東西,其實我們的老祖宗早就有了“摸脈”的說法,現在的SOA、ESB之類的東西是不是就像打造一個企業的“神經脈絡”,而“OO”是不是就像“神經元”,它們之間的通訊就是靠生物電脈沖,這就是消息驅動。
《領域驅動設計》一書中只是強調了業務的水平分割,然而在大項目裏還有垂直分割,註意垂直分割不完全等同於包的劃分。目前有一種非常錯誤的做法,就是一上來就開始對象建模,然後再進行歸類劃分模塊;正確的做法應該是前期以確認領域邊界功能為主,後期以確認領域內的對象模型為主。關於領域的切分,《領域驅動設計》沒有過多談及,其實方法就是不斷對企業業務知識的學習和分析。當你對一個業務認識不清的時候,最好的辦法就是不同企業環境下去分析這個業務,那這個業務的所有發展變化就清楚了,這就像那些生物學家總是喜歡通過長期的野外考查來學習知識。這個工作做好了,項目就成功了50%。
領域的邊界就是服務,也是對外提供服務的唯一入口。領域服務和領域對象模型是一個業務領域的2個不同側面。領域服務強調是從外向內看,反映了“外部對業務領域的使用功能”;領域對象模型強調業務領域就像一個獨立的具有一定自主能力的生命體,反映了“業務領域的內部運行機制”。領域對象模型的功能是不能對外暴露的,不然會造成外部對領域對象的耦合。
不要一說“面向關系設計”就是錯的。因為用戶的角度看,業務本來就是面向關系和過程的,這非常自然;而從設計看,業務是不同主體在相互作用。這就是為什麽越靠近用戶的地方面向關系和過程的設計味道越濃的原因了。
“類和職責”的叫法讓我總感覺比較僵化,像是沒有生命的死細胞一樣,覺得這是一種西醫模式。我更崇尚一種中醫模式,強調建模是動態的、基於場景交互的,應該用更自然的還原業務本來面目的眼光去審視建模過程,也就是說“有機的業務建模”實際上就是“技術建模”的問題域建模,而“技術建模”只是“業務建模”的技術落地而已。
關於建模工具,像“用例圖,流程圖,狀態圖之類”的並不是我理想的建模工具,雖然他們確實能表達一些東西。我理想的業務建模工具應該是能從角色(組織或者人)、流程、業務能力三個維度立體地、動態地分析描述業務模型,希望可以是一個動態的3D視圖和流圖,並可以按不同的維度分析展開。
那對於我們做企業業務建模,終極目標應該是個什麽樣子呢?我認為這個終極目標一定是非常復雜的(也就是我原來常說的大項目場景),因為只有在復雜的場景下才能真正檢驗各種建模技術的偏頗。想想看,我們的建模目標應該向誰學習。論壇也有人說過,“自然的就是最好的”。是啊,經歷過億萬年才進化出來的模型難道不值得我們學習嗎,難道不是我們的目標模型嗎!呵呵,答案已經呼之欲出了,就是“仿生物建模”。是的,沒錯,如果說利用我們的建模技術能夠去構建出一個復雜的仿真人,具備人的一些特征和功能的話,那這種建模技術就是完美的。
企業的業務建模可以分為兩個層面,”宏觀建模”和“微觀建模”。“宏觀建模”是指首先要對企業做一個整體的信息化規劃,對企業進行整體的的業務架構建模,其成果就是業務組件。其中的方法論可以參照IBM的CBM,不過IBM好像也只是咨詢,真正的落地還要靠自己對CBM的領悟。Evans的DDD主要屬於“微觀建模”部分。對於“微觀建模”,我認為分為2個方面:“結構化建模”和“行為建模”,這是一體兩面。我覺得Evans對DDD總結了幾個關鍵的要素:實體、值對象、聚合、工廠和存儲,但其中還少了一個非常重要和關鍵的要素:“事件”。
眾所周知,人體是由很多細胞構成的,那細胞之間是如何作用的呢,其實就是“刺激”和“響應”。其中“刺激”就是“事件”,所以“事件”是業務模型本來就應該具備的要素,而不是什麽技術層面的東西。從“事件”角度看,“職責的本質就是事件的響應”。
“結構化建模”是指建模中除了靜態的實體和值對象的結構關系外,從“事件”角度看,實體或者值對象還具備一些“本能的反應”,比如"手指會彎曲"。而“行為建模”是指通過神經中樞(消息總線)來控制不同對象的本能反應來完成一個復雜的組合,比如"用手彈鋼琴"。
“一上來先識別類,然後就考慮怎麽分配職責”的做法是一種本末倒置的僵化的靜態建模。這種方式往往讓人落入一種只註重“形”而忽略“意”(業務本來的面目)的怪圈。我認為建模分為2個階段,第一個是“有機的業務建模”,第二個是“技術建模”。“業務建模”和“技術建模”的區別是:“業務建模”完全是業務語言,不含任何技術成分,比如“類、值對象和職責”的概念,在“技術建模”中才涉及那些概念。“業務建模”做好了,“技術建模”就成了自然而然的東西了。“有機的業務建模”的一個非常重要的特征就是“有機”,就是強調業務模型中的每一個“業務主體”都是一個生命體。這些業務主體都有“生命特征”,在一定條件下受到外界的刺激就會發生一定的行為。這些業務主體構成了整個業務模型。當然,這些業務主體的規模和層次不同:比較大的業務主體就是“領域主體”,他有明確的領域邊界;而領域主體的對外界響應其實是通過內部的“業務核心主體”的協作來完成的,有的看見的見摸得著————具有業務實體的特點,有的比較抽象————控制規則和流程,當然有的“業務核心主體”可能是個多核細胞。“有機的業務建模”有一個非常重要的工作就是“檢查業務模型的生命健康狀況”。需要註意的是這個業務建模可能是通過不完善的用戶需求建立起來的,所以我們需要構建多種場景通過不同的刺激去看這個領域主體內部的響應中是否有“異常情況”,如果有那就要開刀了。關於“技術建模”,我認為“對內功能和對外功能要分開”,領域對象不建議同時承擔對內和對外的功能,但小項目除外。服務對外要封裝和隱藏領域內部的東西,提供的是服務接口;同時服務要負責領域內部對象的行為組裝。從另外一個層面看,服務是需求,領域對象模型是實現。值對象的本質就是反映業務主體的不同業務特征,可能是業務主體的臨時狀態(比如用戶的發帖數)或者屬於另一業務主體的狀態值。從微觀看,聚合是交互最緊密的業務對象的封裝,從宏觀看,聚合是一個具有明確業務邊界的獨立業務核心主體。所以聚合只是形式,業務模型的正確建立才是決定要素。 
相互作用原則全面、深刻地揭示了事物之間的因果聯系,是因果關系在邏輯上的充分展開。在客觀世界的普遍聯系鏈條中,原因和結果經常互移其位、相互轉化。受原因作用的事物在發生變化的同時也反作用於原因,從而把因果性關系轉變為相互作用的關系。其中每一方都作為另一方的原因並同時又作為對立面的反作用的結果表現出來。整個物質世界就是各種物質存在普遍相互作用的統一整體,相互作用是事物的真正的終極原因,在它之外沒有也不可能有使它運動和發展的原因。相互作用也是系統內部諸要素的關系和聯系的形式。要素之間相互作用的方式構成系統存在的基礎,系統中要素的相互作用是決定系統發展方向的因素。相互作用只有借助於特殊的物質載體才能實現,相互作用的內容取決於組成要素的物質層次和性質。例如,現代生物學把相互作用劃分為分子的、細胞的、器官的、機體的、種的、生物圈等不同水平的形式。社會生活是最復雜的相互作用的形式。 相互作用是客觀的、普遍的。具體的相互作用是整個物質世界相互作用鏈條的環節和部分,相互作用的普遍性和絕對性通過無限多樣的具體的相互作用而體現出來。相互作用是事物的屬性、結構、規律存在和發展的條件。相互作用範疇具有重要的方法論意義。認識事物意味著認識它們的相互作用,要揭示事物的本質屬性,就必須研究事物之間具體的相互作用的特殊性。相互作用的實質是矛盾以及矛盾諸方面的相互依存和鬥爭。在諸多因素的相互作用中,必有一種起著主導的決定的作用。在實際工作中,只有認清事物之間相互作用的特點和規律性,才能認識和把握事物的本質。 “事件”這個詞的確有技術範疇的嫌疑,但說到“相互作用”、“輸入和輸出”,大家都會明白的。過去的OO過於僵化、教條,偏重於靜態場景,忽略了客觀世界運動和相互作用的本質規律,而最近出現新技術和對OO的反思“正在回歸自然”。
“世界是有事物及其活動組成”或者“世界由事物及其相互作用組成”是非常樸素、直觀的世界觀。
建議學習“經過億萬年進化而來的客觀存在的生物控制模型”,我們都知道“人體是通過神經網絡來控制不同的肌肉、骨骼來做出各種復雜的動作的”。“刺激和響應”是客觀存在的,而“場景”只是我們對客觀世界的主觀認識。“刺激和響應”,舉個例子,人的最外層的皮膚就如同“門面”,用來接受外界的“刺激”,內部再由“大腦”下達指令,指揮各個“肢體”進行“響應”。 “神經網絡”是被這層皮膚覆蓋加以保護。 “神經元”向“皮膚”註冊可能完成的“響應”,而“皮膚”接受“刺激”後由大腦進行反饋而回調“神經元”,“神經元”再完成各個指令動作。
業務建模應該遵守客觀規律。
DDD強調“充血模型”。在復雜業務中,這很有用,可以提高對象的可復用性。但是要註意,“充血模型”雖然很好,但其背後卻隱藏玄機。復雜場景中,如果所有的行為都放到了對象中,那領域對象就會變得沈重無比,帶來各種副作用。同時,描述狀態的值對象往往不是一蹴而就,而是充滿著變化,難以把握。當業務不明時,"貧血模型"容易把握,這也就是為什麽現在”充血模型“不多,而"貧血模型"大行其道的原因。
DDD認為"領域對象應該是有行為的",大家都認可。如果說"貧血模型"造成了對象和行為的分離的話;那麽"充血模型"也是有問題的,因為DDD中簡單地認為把行為放到對象中就行了,殊不知這其實是關於對象和行為之間的一種靜態地僵化的看法。而DCI對這種思想進行了修正,認為對象在場景中才具有行為。對於DCI中的對象(數據),我認為DCI中的對象(數據)是一種裸對象,但卻不是簡單意義上的"貧血對象"。DCI中的對象和行為是一種動態關系,是依賴於場景而存在的。這也就是說對象不會無緣無故的產生行為,(呵呵,那是神經病),對象具有行為一定是有意義的。也許有人擔心場景會變成"貧血對象"模式下service那樣的噩夢,造成對象和行為的分離。其實不用擔心,在DCI中可以用"事件"把對象和行為聯系在一起就避免了"貧血對象"的問題。呵呵,這是不是應了中國的一句老話:"分久必合,合久必分"。
對於DDD中的聚合,我也有不同的理解。其實DDD提出聚合的概念是為了保證領域內對象之間的一致性問題。但是我對DDD中對"聚合"這個概念的落地形式表示質疑,DDD特別強調聚合根的封裝性,然而這可能會導致領域內對象之間的邏輯強耦合。也許有人說領域內部的對象是高內聚的,這樣做沒關系。但是在實戰中,領域模型內部的值對象往往存在著變數,這是我們認識客觀世界的必然規律。然而這會導致領域模型的不穩定性。所以我認為及時領域內部的對象也應該註意低耦合,這個問題同樣需要靠事件來解決,事件才是保證領域對象一致性的關鍵。
“一致性”究竟是什麽呢,我認為“一致性”是事物相互作用的本質內在聯系,也就是在一定場景下外界刺激在沿著一定路徑傳遞而導致一系列對象的變化。所以“外界不可以繞過根實體直接修改狀態”並不能反應這一本質,因為外界刺激並不全都是先作用在根對象上面的。在我看來,這種非本質的封裝反而會造成耦合,尤其是采用“直接調用”的形式。應該說,“直接調用”是造成對象耦合最大根源,因為“直接調用”是在強調對象的上下級關系,這很生硬。如果我們換一種方式,用一種平等的心態去看待對象間作用關系,用“告訴我做什麽”的方式而讓對象間解耦。
在思考語言範式時,我曾這樣想過,面向對象,行為與屬性綁得太緊,面向過程,行為與屬性放得的太松。但這裏不是僅僅選擇“分”或“合”那麽簡單,“貧血模型”與“充血模型”實際上與“面向過程”與“面向類(對象)”的矛盾是相似的。“貧血對象”是將“行為”與“屬性”完全放開的一種表達,而“充血對象”則又矯枉過正,把“行為與屬性”綁得太緊。類是表達共性的概念,而對象則是充滿個性,而且這些個性是依賴場景的,離開場景將失去意義。所以,在“充血模型”中,用類表達對象時,實際是將“個性”統統視為“共性”,在任何具體的場景中,對象的角色或職責都已經定義好了,這顯然是不合適,因為一個對象可以多種角色參與不同的活動或場景(可能使得類繼承體系非常龐大和復雜),而且在參與新的活動或者場景時,以“類”及“繼承”的方式定義對象則更是力不從心。而在“貧血模型”中,則將“共性”統統視為“個性”,這是抹掉“共性”的做法,與“充血模型”抹掉“個性”的做法剛好相反。前者是“白馬非馬”,後者則是“白馬即馬”。都沒有協調好“共性”與“個性”的關系。因此真正自然的“領域模型”應該是這樣的,如果對象的某些行為在任何場景都是通用的,那麽就放在領域中去,將其綁定,這是尊重“共性”的約束;如果對象的某些依賴於具體的場景,那麽則在具體的場景中註入相應的行為,賦予對象相應的角色,這是尊重“個性”的自由。所以,對象的行為該不該放入“領域模型”,我們要先分析一下這些行為是對象所固有的,還是依賴於場景的,如果是固有的,即是共性的,就放入領域模型(domain),如果不是則延遲在具體的場景(service)中註入,賦予其角色的個性(DCI)。
設計模式可以在領域模型中使用(domain),也可以在具體業務場景(service)中使用。設計模式是在局部、微觀層面的一種支持變化的機制,在具體業務場景中使用再合適不過了。將來可能會出現的現象是,在領域層(domain)各個模型中用的更多是“結構型”模式,而在業務層或服務層(service)的各個場景中用得更多的是“行為型”模式,兩者都可以使用“創建型”模式。
不要把業務和領域等同,業務是客觀存在,領域是主觀認識。
領域和場景是不同的。領域是宏觀層面的,場景是微觀層面的,雖然它們有相似點。
如果可以用一個領域模型來描述“企業”的所有業務,我當然希望是這樣的,但問題是有誰可以做到,那就是共產主義了,完全可以憑此打敗微軟、IBM之類的公司成為老大了。領域“有界無邊”,說起來拗口,簡單說領域雖然有界,但其邊界時可以擴展的,領域雖然有界,但其邊界是無形的。比如說音樂界不斷發展,但界還是存在,雖然界也是一種主觀認識的劃分。因為音樂界不能獨立於人類的所有活動。
領域的邊界是由用戶的需求來決定的,用戶的需求是動態可擴展,所以領域的邊界也如此。所謂領域語言,就是從有所需的用戶心中提煉出來的。用戶需求相對於領域來說是一個“客觀存在”。
領域雖然是對客觀存在主觀上一種劃分,但不是一成不變的。一個領域模型是根據業務(用戶需求)對領域的一種素描,業務不同,素描也就不同。
我們應該學會逆向思考:
1.服務是什麽?自己在過去的項目中用過服務嗎?如果不用,會怎麽樣?如果用了,用好了嗎,出現了DDD指出的問題嗎?
2.聚合是什麽?為什麽要用聚合?自己用過聚合嗎?DDD的聚合采取的形式是什麽?除了DDD中的聚合,還有別的聚合嗎?
對DDD其他的要素可以以此類推。其實DDD不太適合初學者和小項目,DDD是經歷過很多項目的失敗和成功才總結出來的。所以我是反對把DDD當成一種理論學習的,在實戰中不懂得東西不要亂用,但是一定要感悟,也就是說你可以先不去用DDD,但可以在實踐中感悟DDD的思想和要素,然後明悟真偽。所以我發了這麽多帖子,希望大家從自己的實戰去印證,共鳴。這裏不是沒事無聊的閑談,而是基於實踐的關於DDD的靈魂的交流。
DDD是對一些復雜IT項目成功要素的總結而形成的一種理論。正確地理解DDD是關鍵,只要成功運用DDD的思想和要素就可以了,絕不是照搬。就算沒見過DDD,也可能在實踐中運用過DDD的思想和要素。
領域建模與設計模式的思想不是只有高手才能領悟,就像數學與哲學思想不是只由數學家和哲學家才能領悟。思想與知識是兩個相關又不同的範疇,建模思想與技術知識/經驗同樣如此。不要因為新手知識的不足,而認為新手就不能領悟思想。如果出現這種情況,我只有兩種理解:a)這個老手不懂;b)這個老手懂,但不想告訴你,可能出於自私,也可能覺得你還不適合。
不同於設計模式的關註點在如何設計模型以支持需求的變化,分析模式的關註點如何將需求轉化為模型。Martin Fowler的《分析模式--可復用的對象模型》、Peter Coad的《對象模型--策略、模式、應用》等等關於分析模式的著作,都尚未拜讀,加上經驗實在匱乏,所以本不想說。可是對於Peter Coad的《JAVA Modeling in Color with UML》一書中的四色模型,一見如故,極其簡單的四色模型,在我心裏已經將其作為自己關於分析模式的核心認知,這裏說說自己對四色原型的理解(再次感謝Jdon讓我遇見了四色模型)。
四色模型中有四個最核心的概念(剛好設計模式也是運用了OO的四個基本概念,無巧不成書呀),分別是MI(Moment Interval)、Role、PPT(Party Place Thing)、Desc(Description), 不同設計模式運用的OO的Abstraction、Encapsulation、Inheritance、Polymorphism四個基本概念在中文有很好的翻譯:抽象、封裝、繼承、多態。這四個詞,直譯起來,似乎沒什麽感覺:瞬間-間隔時間、角色、聚會場所-物件、描述。查閱一些資料,其描述我不是十分滿意,這裏我嘗試用簡短的言語解釋其本質:MI描述活動,Role代表參與活動的事物;PPT代表未參與活動的事物,Desc描述事物。舉個例子,比如一件商品,商品本身就是PPT,商品的類別信息、廠家等商品的元信息就是Desc,如果這件商品為顧客所購買,此件商品就變成了Role(當然顧客此時也是Role),而顧客購買商品這個活動就是MI。
世界可以簡單理解為由事物及其運動(MI)構成,事物又有動靜之分,動即參與活動之事物(Role),靜即未參與活動之事物(PPT),此外,可能還需要描述事物的信息(Desc)。為了將原型形象化,我們可以根據色彩的冷暖動靜之感,將活動(MI)塗上活躍的紅色,將參與活動的事物(Role)塗以暖色黃色,將未參於活動的事物(PPT)塗以安靜的綠色,將描述事物的信息(Desc)塗以冷色藍色。這樣四色原型就誕生了,通過四色原型,我們可以像孩子拼接積木一樣,一塊一塊地拼接出需求模型的原型了。
分析模式將需求轉化為原型,設計模式支持需求模型的變化,而實現模式為何而生?實現模式關註的是代碼本身,我們在分析和設計上付出的努力,終究要落實在代碼上。分析和設計再好的模型,也可能被充滿smell的代碼掩蓋或破壞。Kent Beck在《實現模式》一書提出了77個實現模式,6條原則和3種價值觀。77個實現模式涉及一些具體的代碼規範的建議,暫且不論;6條原則,局部化影響、最小化重復、將邏輯與數據捆綁、對稱性、聲明式表達和變化率,也暫且不議;3種價值觀:溝通、簡單、靈活,我也只想說說其中的一點:溝通,因為個人認為這是實現模式最根本的意義所在。Kent Beck在書中說:過了20年,把別人當作空氣一樣的編程方式才在我眼中褪盡了顏色。作為一位programmer,代碼的作用不僅在於與機器交流,更重要的是與別的programmer交流,將“溝通”的價值觀貫徹到代碼的編寫中,是值得每個programmer堅持去做的事情。上面所說的三本很薄的書,可以作為關於分析、設計、實現模式的認知基礎,值得收藏。
“領域相對於用戶需求是主觀的”,這句話隱含了一個假設或參照,我們對領域認識的來源於用戶需求,可是用戶需求來自哪裏呢?用戶需求同樣來自於領域,來自於對領域的訴求!之前我的另一個觀點,“領域是對用戶需求的素描”,這句話同樣隱含了一個前提,用戶需求接近於領域的本質,我們對領域的認識可以通過對用戶需求進行素描而實現。這裏我重新確定領域、領域建模、用戶需求三者的關系。
1)領域是客觀的。
2)領域模型是主觀的,體現了程序員對領域的認識,是程序員心中對領域的素描。
3)用戶需求是主觀的,體現了用戶對領域的認識,是用戶心中對領域的素描。
4)這點非常重要,就是“領域模型”與“用戶需求”的關系,要展開來講。“用戶需求”是對領域的“素描”,用戶的需求來自對領域的“訴求”,這些訴求往往是深刻的,因為其來源於用戶對領域長期觀察和使用的經驗,比起我們程序員,一般更完整、更真實地接近領域的本質。我們對“用戶需求進行素描”,就是“借鑒用戶的寶貴經驗”,可以更快、更好地素描客觀領域,這可以說是一條認識未知領域的捷徑。但是當用戶需求不明朗或不清晰時,我們需要超越“用戶需求”,對領域進行深入的摸索,去尋求更清晰的視角,對領域進行刻畫。
關於人(參與者)是否應該包含在領域模型之內?領域模型(程序員對領域的認識)要包容用戶需求(用戶對領域的認識),這就像一個杯子要裝滿一杯水,我們在制作杯子時,制作的是空杯子,即要把水倒出來,之後才能裝下水;再比如,一座房子要住人,我們在建造房子時,建造的房子是空的,唯有空的才能容乃人的居住。從這個意義上來說,領域模型要將用戶(參與者)排除在外,這是《老子》的“無之以為用”觀點的一種應用。
對於對象職責的分配以前看過一本書<<UML和模式應用>>這本書將的非常好。裏面有GRASP原則--通用職責分配軟件模式(General Responsibility Assignment Software patterns),它裏面講了以下幾個模式:
1)創建者(Creator) :
決定對象應該有誰來創建的問題。一般情況下是包含類創建被包含的類,比如Order創建OrderLine等。
2)信息專家(Information expert):
用此模式來確定如何給對象分配職責的問題。一般把職責分配給那些包含此職責有關信息的對象。這樣也體現了高內聚性模式。這裏面其實也是將行為和對象的數據統一起來,分配某個對象職責,就看看當前的對象裏面有沒有完成此職責的數據,如果有就可以分配職責。
3)低耦合(Low coupling)
面向對象的設計,講究對外封裝,對內解耦,一個模塊或者一個類,我們暴漏給外界的接口是粗粒度的,經過封裝的,而模塊或者對象內部需要進行細分,進行解耦,類與類,模塊與模塊之間耦合度越低,那麽可擴展性就越好,維護起來也容易,不會造成牽一發而動全身的局面。
如何使得類於類之間低耦合呢,我覺得迪米特法則非常重要,迪米特法則就是通常說的“不要和陌生人說話”,一般類的行為主要可以由以下幾種形式來實現: 
A. 方法參數中的對象,通過調用方法參數中對象方法來實現職責
B. 對象自身的方法,通過對象自身的方法實現職責
C. 對象內部聚合的對象,通過對象內部聚合的方法實現職責。
D. 方法創建或者實例化的對象方法,通過對象自身創建的對象的方法實現職責
以上四種方式都是我們可以接受的,下面這種方式,我們一般要避免,比如a.methodA().methodB(),調用者對象調用了methodA方法返回的對象的方法,這樣就會使得調用對象和methodB所在對象發生了耦合,此時我們可以完全將methodB的調用封裝在a裏,那麽此時調用者就只與a通信,而不是和a,以及methodB所在對象都耦合在一起。
4)控制器(Controller).
控制器模式主要解決將系統事件處理的職責分配誰的問題,控制器模式指出將處理系統事件的職責分配給控制器類,比如MVC模式中的C就屬於這種模式,還比如Struts中的ActionServlet這個Front controller(前段控制器 J2EE核心模式一書).
5)高內聚(High Cohesion)
一個類如果是高內聚的,那麽類和類之間也將變的松耦合,如果類和類之間耦合太多,那麽勢必類就喪失了內聚性,因此我們在分配職責的時候,高內聚和低耦合是相輔相成的。
6)多態性(polymorphism)
多態性就是OO中的多態,多態其實也是一種具體依賴抽象原則的體現,比如我們有一個產品有個打折策略,而打折策略非常多,那麽這個時候怎麽辦呢?我們當然是定義一個抽象的打折接口,然後將不同的打折策略實現這些接口,而不是讓每個不同的打折策略具有不同的接口。
7)純虛構(pure fabrication)
我們在面向對象的分析和設計當中,難免會遇到一些行為不能很好的分配給實體或者domain model,那麽這個時候就需要虛構出一些概念,比如DDD中的Repository就屬於一種純虛構的東東。
8)間接性(indirection)
間接性從表面就可以知道它是為了解耦的,比如RBAC,通過引入Role將User和Permission解耦,這樣通過引入一個間接的對象,使得原來緊耦合的對象變的松耦合,這樣也方便維護,同時也是為低耦合原則服務的。
9)防止變異(protected variations)
這個原則我們也經常遇到,按照我的理解,它應該是封裝,類似於DDD中的防腐層,軟件系統中的子模塊或者子系統應該將不確定的因素封裝在內部,而不要因為子模塊而影響到外部系統。其實這也是一種封裝思想的體現。

延伸阅读

    评论