我在《
小议领域模型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. 其它
还没有想到,想到再说。