DDD 我的理解

都在谈论DDD 我想说说我的看法,不知对否,望大家执教

所谓的 DDD无异于将所有的业务抽象到领域层,所有的都是对象,所有的对象对自己负责,具体实现时,我的思路是这样的:

首先对业务领域建模,摈弃以往的以数据为中心的思想,首先不考虑哪些需要持久化,尽管根据业务流程进行建模,建模完成后,到了我们考虑哪些数据需要持久化了。从领域对象中找出需要持久化的数据模型,再次审视所有的业务对象的职责,或者通俗的说 ,方法,把握一个尺度,对于所有与持久化相关的操作,如果是简单的CRUD则放到对应DAO中,涉及查询等放到仓储中查询,使用工厂进行对象创建,如对于Lazy-load之类的问题则可以通过仓储和工厂解决。大颗粒度操作抽象到对应服务中。最后就是再次在更高的层次审视整个模型,必要时使用Facade 模式,在系统最上方加一层,如果涉及团队或老系统集成,在必要的Cotext中添加anti-coruption层……

望大家指教

差不多,不过要注意DDD重点是如何对复杂系统建模,也就是找出模型,区分实体 值对象和服务,这些都是难点,也体现建模者的创造性。

就是阿

说起来感觉自己很容易,真正进行建模了才发现憋了半天也就画了几个类图,仔细一看才发现那些就是需要持久化的实体对象……

我感觉DDD重要的还是如何抽象出领域对象,这才是关键,其实谁都有心要OO,可能否发现系统中的领域模型不是谁都能做的

>可能否发现系统中的领域模型不是谁都能做的
问题还是在于这个过程是一个创造性过程,也可能是一个经验认识量变到一定程度质变的飞跃,具体案例具体分析,MF在它的分析模式中谈了这个过程中几个常见的模式,可以作为自己实践摹习。Evans在它的DDD书籍中也是大量使用案例来说明这个过程,也属于绕着弯子告诉你方法,但是无法直接告诉你方法。

大家是否一致地认为在领域层只需三种对象:实体,值对象和服务?

>大家是否一致地认为在领域层只需三种对象:实体,值对象和服务
这几个就够了吧,太多也乱,你的意见?

目前我看不出什么不妥,当然还得加上解耦用的工厂和通向数据源的仓储。
我现在比较困惑的是实体映射到关系时,灵活度需要达到多少才合适,比如最适合DDD的通用映射方式:N个实体可以映射到1个关系,M个关系也可以映射到一个实体;实体的N个属性可以映射到1个关系字段,M个关系字段也可以映射到实体的一个属性。继承映射使用类表继承。这样虽然解除了对象和关系的耦合,但也带来了非常大的复杂度,不知实际项目中大家实现的程度怎样?
[该贴被diogin于2007年06月26日 21:50修改过]

我想灵活度的代价肯定是有的,具体的尺度把握就要看项目的具体要求和经验 了……

还有一个问题就是,实体和服务的职责划分 ,哪些操作要放到实体里,哪些要丢到服务中,有些思路是按照是否依赖持久层,也就是说,凡是和DAO 或仓储打交道的职责都要丢到服务中解决,不知道这种思路对否,要么实体对象就要和仓储耦合了估计%%

>我现在比较困惑的是实体映射到关系时,灵活度需要达到多少才合适
关联关系尽可能少,能够没有最好,考虑设计关系尽量从谨慎扼杀角度出发。要反复推敲每个你设立的关联关系,不要随便设立关联。

>实体和服务的职责划分 ,哪些操作要放到实体里,哪些要丢到服务中
这个我在另外一个帖子中也提到:必须判断哪些特征是属于该对象固有基本的;哪些则不是,哪些和应用特征相关的服务性质,比如人存取款这个动作特征,其实和具体应用有关,而不是人对象固有基本的。

这里就有两个极端:一个是将所有操作都放在实体中,如2001年的Jive2.5设计就是这样,最后带来弊端就是每个实体对象很复杂;还有另外一个极端就是实体中没有任何操作,这是MF的批评的失血模型,贫血模型。过去有人当听到MF批评失血模型时,就开始将实体的save等操作放在实体中,这个我个人认为不妥,save属于对象持久化,属于对象生命周期的管理维护动作,一个对象不能自己对自己生命周期进行管理维护,这其实是很正常日常生活常识,我们人都是由父母给予生命的,不可能自己创建自己,万事万物的生命都不是它自己创建的,或它自己来管理维护。

但是,无论哪一种,都和数据库模型毫无关系的,现在又推出一种非数据库,但是也非领域模型的模型设计,他就以网站社区为案例,提出:“我明白Martin在这个主题上的观点,他说要把更多的逻辑关系放到领域模型里,但是如果你的领域模型里不需要任何逻辑,而只是存取数据呢?”

中文翻译:
http://docman.cn/dm/doc.php?id=21

原文网址:
http://thebull.macsimumweb.com/building-a-high-volume-app-without-a-rdms-or-domain-objects/
[该贴被banq于2007年06月27日 10:23修改过]

服务和实体的职责分配倒不是很难,在这一点上,《对象设计-角色、责任与协作》一书有非常详细的讲述。我个人认为实体的持久化操作之类的职责不应该放到实体中去,而应该由仓储负责,仓储和实体则被控制者负责调用和管理。另外服务要想与仓储分离我认为不现实,比如一个服务:检查某个实体是否存在,这个服务必然要与仓储关联。当然这个服务基本上不成其为服务,因为太简单了点,但是这些简单的职责加上更强的领域逻辑时就自然被组织成可复用的服务。所以我的观点是:实体不应该有持久化的职责,实体应该是被动的(或者判断自身的某个约束,比如权限是否达到某个要求,这个责任说不上被动和主动);服务可以关联实体和仓储;控制者可以关联实体、仓储和服务。

>关联关系尽可能少,能够没有最好,考虑设计关系尽量从谨慎扼杀角度出发。要反复推敲每个你设立的关联关系,不要随便设立关联。
实际上我是想知道,实体与关系的M:N对应的情况有多少价值。比如RoR是1:1对应,就DDD来说这只能算是其中最简单的一种模型。通用型的实体与关系映射应该是M:N,就提取实体时来说,是无需考虑数据源设计的,所以必然存在非一一对应的映射。
>还有另外一个极端就是实体中没有任何操作,这是MF的批评的失血模型,贫血模型。
我认为没必要拘泥于某些所谓的大师的言论。他是有批评贫血模型的倾向,但很多情况下确实需要这种模型。在他的《企业应用架构模式》一书中他就说过他不喜欢服务层,这么一来他就会把原来应该抽象成服务的一部分责任放到实体中去,这是很荒谬的,违反了面向对象基本的单一职责原则。DDD里会存在一种情况,就是服务操纵所谓的贫血模型。这在范式上跟面向过程很相似。所以就这一点来看,面向过程与面向对象的区别并没有号称的那么大。实际上,我认为凡事按我们日常的思维原则来设计最合适,而不是拘泥于某些理论。

>他是有批评贫血模型的倾向,但很多情况下确实需要这种模型
我感觉也是,比如一个网站的用户排行榜,这个简单的东西我想一般我们都会只根据数据库中的所谓积分等直接排就是了。可如果你仔细看看Topcoder 上的排行规则,估计凡是有些OO经验的都会弄出一大堆所谓的领域对象来实现他的排行功能。
而我们平常的排行榜,谁又会,或者谁又能弄出那么多的领域对象呢?
我感觉,所有的所谓贫血或充血模型都是相对的,也是随需而变得,一味的强调一些东西还是很没意思的

一年前做项目,总是先在PDM上把数据库表结构建立好,然后才开始做项目,当时认为数据库表结构设计很重要。
今年年初,开始接触JDON论坛,发现网上流行域建模,换个名字说就是先建立实体。
深有同感,但是一直在工作中没实际接触过,只是有个印象。
今年换了一家公司,新公司就是先建立实体,然后使用ANT自动生成HIBERNATE配置文件和数据库的。实践了一段时间,感觉很舒服。

>DDD里会存在一种情况,就是服务操纵所谓的贫血模型。这在范式上跟面向过程很相似
这种情况只有在一部分业务系统才会出现,例如我上一个帖子提到的老外博客网站社区那个例子,也就是说:MF认为应该将业务逻辑放在领域模型中,但是如果我们业务系统的业务逻辑很简单,甚至没有,那么我们的模型就很简单,是一个简单数据模型了。

我个人认为不能因为一个特例就认为这和面向过程相似,面向过程概念很广,并不是每个方面都不好,而是有一个主要缺点,主要缺点我认为就是将业务逻辑放在服务中了,而不是模型中。

将业务逻辑放入服务中缺点很多:不能方便改变前后逻辑执行顺序,过去EJB中Session Bean常被用来实现服务,很多人还是面向过程思维,结果将业务逻辑很自然放到Session bean中,还以Facade模式自我安慰,这样的系统在业务需求变化时,很难敏捷跟上变化,还是一个传统面向过程系统,这些做法受到OO派疯狂批判,最后EJB技术本身成了替罪羊。到了EJB3,如果你将业务逻辑还是放在你的POJO服务类,还不是回到过去?这种现象同样存在Spring等其他框架应用中,Jsp+JavaBeans中更严重,甚至初学者将业务写在Jsp中,这样的系统可以说都是面向过程思维惹的祸。

所以,重要的是程序员自己的编程思想改变,而不是技术平台简单升迁。
[该贴被banq于2007年06月28日 19:03修改过]
[该贴被banq于2007年06月30日 19:49修改过]