我在《
小議領(lǐng)域模型Domain Model》討論了service和object,以及關(guān)聯(lián)邏輯(咳咳,該文中的一些觀點(diǎn)我已修正,合適的時(shí)候放上來(lái))。關(guān)聯(lián)邏輯就是本文討論的重點(diǎn)--specification
一、從DDD(Domain Driven Design)說(shuō)起
這個(gè)Specification來(lái)自DDD,DDD有對(duì)specification分為三個(gè)類型
1. Validation
2. Selection
3. Building
不過(guò)在初看這個(gè)Specification的概念的時(shí)候,相信很多人都有一種似曾相識(shí)的感覺(jué)。我們?nèi)粘i_發(fā)中, 基于SRC原則寫的那些xxxxProvider,xxxHelper,xxxChecker,而此外還有討論了無(wú)數(shù)遍的Dao。不就是這個(gè)specification嘛,換了一個(gè)馬甲嘛。
二、應(yīng)用Specification的好處:
現(xiàn)在就是我要高舉specification的理由了。
1. 統(tǒng)一Domain model的相關(guān)支持邏輯,屏蔽了dao的存在。
請(qǐng)注意這個(gè)selection,即從repository中(通常是數(shù)據(jù)庫(kù))取出合適的對(duì)象列表。嗯,這個(gè)有意思了,原來(lái)總覺(jué)的dao在系統(tǒng)中的地位挺尷尬的,
由于先前的開發(fā)理念,Domain Model沒(méi)有出現(xiàn)之前,我們是Transaction Script的開發(fā)模式,在ORM技術(shù)出現(xiàn)后,從TS轉(zhuǎn)向Domain過(guò)程中,數(shù)據(jù)庫(kù)訪問(wèn)轉(zhuǎn)成dao層, 大量的約束邏輯則散落在Service層中。因而開發(fā)系統(tǒng),無(wú)論是那張系統(tǒng)結(jié)構(gòu)(架構(gòu))圖中(可以參考AppFuse),我們見貫了Dao層的存在,甚至我們習(xí)慣了Dao的存在。
而應(yīng)用Specification則統(tǒng)一了這些概念,屏蔽了dao。dao做的最多的工作是查詢邏輯,而查詢邏輯也是一種邏輯嘛,和validation以及building都是支持Domain Model。這個(gè)specification算是給dao正名了。不過(guò)概念上正了名,如果僅僅在于此,恐怕大多數(shù)人都會(huì)說(shuō)“嗯,不錯(cuò),但是還是那么不實(shí)用”:要是按specification的做法,也就是把dao的下的代碼分散出去,沒(méi)有獲得太多的好處,搞不好還給背上類型膨脹的罪名。別急DDD還有后手呢。
2. Specification引入了FP的開發(fā)思路
DDD可不是技窮于此,隨后就提出了specification的closure。明眼人一看就知道這個(gè)closure來(lái)自FP。
回顧一下函數(shù)式編程基本特性先: 1. 閉包計(jì)算和高階函數(shù)。 函數(shù)本身是first class對(duì)象,閉包是起函數(shù)作用并可以像對(duì)象一樣操作的。高階函數(shù)是可以接受一個(gè)函數(shù)為參數(shù),并可以返回一個(gè)函數(shù)。 2. 延遲計(jì)算(lazy evaluation) 不是在函數(shù)綁定時(shí)計(jì)算,而是在求值時(shí)計(jì)算。 3. 遞歸的計(jì)算機(jī)制 4. 引用透明 同樣的輸入返回同樣的結(jié)果,與上下文無(wú)關(guān)。 5. 沒(méi)有副作用 賦值后不能更改,即是constant |
現(xiàn)在看看DDD三種specification的組合情況。
1. Validation的組合,DDD也給出了例子代碼--看著就清爽!
2. selection的組合,DDD并沒(méi)有給出例子。也不幸就是這個(gè)selection比較難辦,因?yàn)樯婕暗絪ql問(wèn)題(這個(gè)問(wèn)題往往又和性能連在一起)。剛好javaeye上有人開貼討論組合sql的問(wèn)題(http://forum.javaeye.com/viewtopic.php?t=21760)
我的想法是:從domain object的角度把selection的組合范圍限制在where和order兩個(gè)clause。
這是最簡(jiǎn)單的,不考慮select和from,更不考慮join了。對(duì)于同一domain object其where和order的組合是簡(jiǎn)單的。DDD一書中的and,or和not操作是容易支持的。
接著要考慮支持join和union了。我估計(jì)應(yīng)用系統(tǒng)中:普通的sql(不帶join和union),帶join和union的sql以及更復(fù)雜的sql語(yǔ)句的比例是4:4:2。
不過(guò)join處理實(shí)在麻煩,我需要一些額外的信息。所幸從試驗(yàn)的代碼看起來(lái)還是可以接受的。
那么對(duì)于那些確實(shí)復(fù)雜的sql查詢?cè)趺崔k(那剩下的2)?簡(jiǎn)單。單獨(dú)寫一個(gè),我的觀點(diǎn)是太復(fù)雜的東東復(fù)用的可能性也不大,日后出現(xiàn)類似的東東可以考慮用OO的繼承的方式搞定,CO和OO本來(lái)就不是相互排斥的。
除此外,還有和domain object無(wú)關(guān)的”分頁(yè)”以及”top n”就可以獨(dú)立提供specification來(lái)。
(BTW:ajoo說(shuō)不能光說(shuō)不練,準(zhǔn)備和buuawhl在sql的parser上作文章了。向偶像學(xué)習(xí),抓緊試試看能不能作出來(lái)。)
3. building的組合
這個(gè)看起來(lái)像curry,沒(méi)有想好,暫時(shí)不討論。
除此之外,系統(tǒng)中其它很多邏輯可以用FP的思想做,如業(yè)務(wù)規(guī)則(業(yè)務(wù)規(guī)則分類看《DSL:基于規(guī)則系統(tǒng)組織業(yè)務(wù)規(guī)則》)中的Computation,至于業(yè)務(wù)規(guī)則的Constraint和Action enabler可以直接參考validation。
BTW:ajoo在javaeye的blog給出了一些很好的例子。
三、其它問(wèn)題
到目前為止,一些看起來(lái)都還不錯(cuò)。但是還有幾個(gè)問(wèn)題沒(méi)有解決:
1. Selection的組合問(wèn)題是否真的可以實(shí)現(xiàn)。
這個(gè)。。。嘗試中
2. 難道在開發(fā)中要為每一種類型的specification單獨(dú)寫組合操作的處理函數(shù)。難道不能有一種統(tǒng)一的。
到目前為止,還不能。 對(duì)于各個(gè)specification,無(wú)論是參數(shù)還是返回對(duì)象的類型,以及組合的細(xì)節(jié)都不同,我們不得不獨(dú)立處理。
2.1 首先是參數(shù)還是返回對(duì)象的類型,真的統(tǒng)一的話,就會(huì)變成這樣:
interface Action{ Object execute(Context ctxt); } interface Context{ Object get(String key); } |
很明顯這不是我們要的
2.2 另外就是組合細(xì)節(jié)問(wèn)題:
buuawhl在
http://forum.javaeye.com/viewtopic.php?t=21533中列舉了3個(gè)不同類型都是我們要考慮的
3. 其它
還沒(méi)有想到,想到再說(shuō)。