banq不在?

我觉得不应该简单的说crud,而是与domain的持久化有关的部分,确实应该放入到domain中。

我觉得不应该简单的说crud,而是与domain的持久化有关的部分,确实应该放入到domain中。

MF和ERIC EVANS都主张富模型,也就是说如果这个服务(涉及增删改)的确是这个类的职责,那么这些服务应该放在这个类中成为富模型,而不是让类成为POJO

谢谢上面的两位,但是正如banq说的。一本书无法删除创建自己一样。crud在jdon中是放在service中的。唉。。。

不是在类中加了CRUD就成为了rich model 。

"crud在jdon中是放在service中的"

没办法,java中实现完全的充血模型比较别扭。

domain模型中要有“业务方法”,也是将业务逻辑方法分散到domain中去,CRUD是执久化操作,不应该放进去。

"CRUD是执久化操作"

可惜啊,90% 的系统的业务逻辑,都包含 crud.

其实CRUD和domain是两个概念,CRUD是domain持久化概念,怎么理解呢?就像人和睡觉。 人去睡觉就是CRUD,但是睡觉不是人的唯一活动,人更多活动是业务工作。

再打个比喻:打开记事本编辑文本,离开后会保存,保存这个行为就类似Domain的CRUD。编辑文本是Domain,这是我们主要业务重点和核心。

为什么我们会发现:90% 的系统的业务逻辑,都包含 crud?用上面记事本概念就好理解,因为你每编辑文本的一个字就保存一次(注意文本字相当于Domain,保存一次就是CRUD操作),所以一篇文章编辑下来,我们看到的是:90%都是保存动作(也就是CRUD)。

如何改变这种状况,就是为Domain开辟一个新的活动空间:内存缓存。

以前Domain的活动空间缺省就是数据库或硬盘,当初是防止丢失重启资料没有了,这个概念在强大服务器端根本无需担心,7x24集群云计算,几乎没有当机可能,你就要抛弃不断保存到硬盘上持久化的老毛病。

这样,Domain Model就有两个活动空间:内存缓存和数据库硬盘。就象人工作上班空间和睡觉空间不一样。

现在,我们程序员通常要手工照顾内存缓存到数据库硬盘实现,因为内存总是有限的,总是要通过代码CRUD来实现数据库持久化,虽然频率不要那么频繁,最终写到硬盘上让人放心才是真正永久保存。

这就有两个思路:在关机维护时花几个小时一次性写数据库关机;有一个产品定时的自动为我们将内存缓存中数据保存到数据库硬盘,无需程序员手工CRUD指明。现在云计算开源产品“兵马俑”已经能够实现这点。

>因为内存总是有限的,总是要通过代码CRUD来实现数据库持久化,虽然频率不要那么频繁,最终写到硬盘上让人放心才是真正永久保存

前面我从总体思路谈了一下CRUD和domain的关系,在目前阶段,我们还是完全无法回避CRUD,虽然CRUD是一个脏活,不得不干。但是怎么干还是要遵循我上面的总体思路。

如果CRUD放在Domain中,如InfoQ案例中,Borrower的CRUD是通过Autowired IOC自动配对的BorrowerRepository来实现,比如BorrowerRepository的方法:Borrower load(long borrowerId),这里面有些歧义:Borrower竟然自己load自己,虽然load返回的Borrower 和当前Borrower 不是一个实例,但是这从概念上就很难理解,我们借助一个空的对象方法取得这个对象?现实中有这种情况吗?很神奇啊。

所以我们应该换一下思路理解:这个案例中orrower的CRUD应该代指业务行为。

将CRUD放入Domain一定要避免持久化技术细节影响到Domain,这是该文作者以及我们共同的意思,该案例通过在Borrower引入接口BorrowerRepository,在BorrowerRepository接口实现中耦合聊持久化场景JPA的annotation,是否违背这一宗旨,也是值得讨论的。如果你从面向接口来理解,只要两者通过接口解耦就可以了,那么这么做也许可以。

而我个人则是将CRUD放在Service中实现,这可以在JiveJdon3代码中看出,在JiveJdon3中,就有复杂的Domain业务行为了,就不象这个案例这么简单,在这种情况下,将业务放入Domain中,但是你看到ForumMessage这个Domain Model中没有太多业务方法,这里因为我们又使用了对象设计原则,如果将所有业务方法在代码上都整合入ForumMessage中,无疑增大ForumMessage复杂性,因此使用代理模式等,我们设计了ForumMessageRender等这样代理或装饰对象来分离业务方法,但是这些都在Model包下,表示他们都属于Domain的。
http://www.jdon.com/jdonframework/jivejdon3/index.html

所以,但就具体持久化CRUD动作来说,JiveJdon3和infoQ这个老外案例有区别,但是总体DDD设计原则是一样的,CRUD属于脏活,不是主要因素,放在Domain与否也许已经不是讨论重点了。
[该贴被banq于2009-02-06 13:57修改过]

虽然CRUD属于脏活,不是主要因素,放在Domain与否也许已经不是讨论重点了。

但是这里我想说一下我的一些细微想法:
1.业务方法必须放在Domain Model,但是业务方法一复杂,还是必须使用细节设计原则分离出去,螺旋式上升,仅仅从代码上看似乎又回到贫血模型当初。所以,不如在代码细节缺省情况下不要把太多方法放入Domain Model代码中,包括CRUD。

2. 如果你有分布式云计算(EJB)设计背景,那么你就会考虑到DOmain Model在多台服务器之间如何实现传送,当然代码越小性能越好,这也是EJB3倡导者推荐贫血瘦模型原因。

综合以上考虑,JiveJdon3缺省是将CRUD脏活放在Service,但是业务行为并不放在service,这是符合DDD主要精神的,从另外一个角度讲:infoQ这篇文章作者只是写一篇介绍DDD文章,并不是真正成熟综合权衡的结果,而JiveJdon3是的。


[该贴被banq于2009-02-06 14:16修改过]

我这里再补充解释一下:90% 的系统的业务逻辑,都包含 crud

看看下面两张图的区别,主要CRUD操作以什么为核心的区别,一个是以Domain Model为核心,这是我们推荐的,一个是以业务操作过程为核心,也就是说,在业务方法实现中经常进行CRUD数据库操作,所以造成CRUD到处都是。



针对infoQ案例中将CRUD仓储方法放在Model中,我又重新阅读一遍DDD这本书。

书中仓储repository与框架关系 与工厂关系章节中谈到:工厂与仓储的区别是:工厂是创新新的对象,而仓储是寻找旧的对象。作者指出工厂和仓储理论上可以融合在一起,实际情况还是要求分开。

从这里可以看出,仓储和工厂属于同一类类型,生产制造类型,虽然他们制造原理不一样,一个是新造,一个是从数据库获得数据重建。

我们已经明确知道,制造者本身和制造产品属于两种不同对象,不能混合在一起,而InfoQ这个案例将仓储repository制作者混合进入制造产品本身,虽然打着DDD名词,但是已经违背DDD背后更深的基本对象概念,因此有误导之嫌。

鉴定完毕。
[该贴被banq于2009-02-06 17:39修改过]