我在《小議領域模型Domain Model》討論了service和object,以及關聯邏輯(咳咳,該文中的一些觀點我已修正,合適的時候放上來)。關聯邏輯就是本文討論的重點--specification
 
一、從DDD(Domain Driven Design)說起 
   這個Specification來自DDD,DDD有對specification分為三個類型 
   1. Validation 
   2. Selection 
   3. Building 
   不過在初看這個Specification的概念的時候,相信很多人都有一種似曾相識的感覺。我們日常開發中, 基于SRC原則寫的那些xxxxProvider,xxxHelper,xxxChecker,而此外還有討論了無數遍的Dao。不就是這個specification嘛,換了一個馬甲嘛。
 
二、應用Specification的好處: 
   現在就是我要高舉specification的理由了。 
   1. 統一Domain model的相關支持邏輯,屏蔽了dao的存在。 
   請注意這個selection,即從repository中(通常是數據庫)取出合適的對象列表。嗯,這個有意思了,原來總覺的dao在系統中的地位挺尷尬的, 
   由于先前的開發理念,Domain Model沒有出現之前,我們是Transaction Script的開發模式,在ORM技術出現后,從TS轉向Domain過程中,數據庫訪問轉成dao層, 大量的約束邏輯則散落在Service層中。因而開發系統,無論是那張系統結構(架構)圖中(可以參考AppFuse),我們見貫了Dao層的存在,甚至我們習慣了Dao的存在。 
  
   而應用Specification則統一了這些概念,屏蔽了dao。dao做的最多的工作是查詢邏輯,而查詢邏輯也是一種邏輯嘛,和validation以及building都是支持Domain Model。這個specification算是給dao正名了。不過概念上正了名,如果僅僅在于此,恐怕大多數人都會說“嗯,不錯,但是還是那么不實用”:要是按specification的做法,也就是把dao的下的代碼分散出去,沒有獲得太多的好處,搞不好還給背上類型膨脹的罪名。別急DDD還有后手呢。 
  
   2. Specification引入了FP的開發思路 
   DDD可不是技窮于此,隨后就提出了specification的closure。明眼人一看就知道這個closure來自FP。

回顧一下函數式編程基本特性先:
1. 閉包計算和高階函數。
函數本身是first class對象,閉包是起函數作用并可以像對象一樣操作的。高階函數是可以接受一個函數為參數,并可以返回一個函數。
2. 延遲計算(lazy evaluation)
不是在函數綁定時計算,而是在求值時計算。
3. 遞歸的計算機制
4. 引用透明
同樣的輸入返回同樣的結果,與上下文無關。
5. 沒有副作用
賦值后不能更改,即是constant

 
   現在看看DDD三種specification的組合情況。 
   1. Validation的組合,DDD也給出了例子代碼--看著就清爽! 
   2. selection的組合,DDD并沒有給出例子。也不幸就是這個selection比較難辦,因為涉及到sql問題(這個問題往往又和性能連在一起)。剛好javaeye上有人開貼討論組合sql的問題(http://forum.javaeye.com/viewtopic.php?t=21760) 
   我的想法是:從domain object的角度把selection的組合范圍限制在where和order兩個clause。
   這是最簡單的,不考慮select和from,更不考慮join了。對于同一domain object其where和order的組合是簡單的。DDD一書中的and,or和not操作是容易支持的。 
   接著要考慮支持join和union了。我估計應用系統中:普通的sql(不帶join和union),帶join和union的sql以及更復雜的sql語句的比例是4:4:2。 
   不過join處理實在麻煩,我需要一些額外的信息。所幸從試驗的代碼看起來還是可以接受的。 
   那么對于那些確實復雜的sql查詢怎么辦(那剩下的2)?簡單。單獨寫一個,我的觀點是太復雜的東東復用的可能性也不大,日后出現類似的東東可以考慮用OO的繼承的方式搞定,CO和OO本來就不是相互排斥的。
   除此外,還有和domain object無關的分頁以及”top n”就可以獨立提供specification來。
   (BTW:ajoo說不能光說不練,準備和buuawhl在sql的parser上作文章了。向偶像學習,抓緊試試看能不能作出來。)
  
   3. building的組合 
   這個看起來像curry,沒有想好,暫時不討論。 
  
   除此之外,系統中其它很多邏輯可以用FP的思想做,如業務規則(業務規則分類看《DSL:基于規則系統組織業務規則》)中的Computation,至于業務規則的Constraint和Action enabler可以直接參考validation。
BTW:ajoo在javaeye的blog給出了一些很好的例子。
 
三、其它問題 
   到目前為止,一些看起來都還不錯。但是還有幾個問題沒有解決: 
   1. Selection的組合問題是否真的可以實現。 
   這個。。。嘗試中 
   2. 難道在開發中要為每一種類型的specification單獨寫組合操作的處理函數。難道不能有一種統一的。 
   到目前為止,還不能。 對于各個specification,無論是參數還是返回對象的類型,以及組合的細節都不同,我們不得不獨立處理。 
   2.1 首先是參數還是返回對象的類型,真的統一的話,就會變成這樣:

interface Action{
  Object execute(Context ctxt);
}
interface Context{
  Object get(String key);
}

   很明顯這不是我們要的 
   2.2 另外就是組合細節問題: 
   buuawhl在http://forum.javaeye.com/viewtopic.php?t=21533中列舉了3個不同類型都是我們要考慮的 
   3. 其它 
   還沒有想到,想到再說。