领域模型的概念

转自:http://nowise.blog.hexun.com/32880455_d.html

自从Martin Fowler的DDD(Domain Driven Develop 领域驱动开发)提出来之后,无数的人就开始非议ORM方式下的持久化实体类,抨击这种方式下的实体类是“贫血”的,缺乏丰富业务语义的。其实他们都犯了一个最基本的逻辑错误 - 偷换概念。

 

概念是如何被偷换的呢?请注意,领域模型(Domain Model)是一个商业建模范畴的概念,他和软件开发并无一丝一毫的关系,即使一个企业他不开发软件,他也具备他的业务模型,所有的同行业的企业他们的业务模型必定有非常大的共性和内在的规律性,由这个行业内的各个企业的业务模型再向上抽象出来整个行业的业务模型,这个东西即“领域模型”。一个掌握了行业领域模型的软件公司,根本不需要再给人家开发项目了,根本不需要靠软件开发养活自己了,你光给这个行业的企业提供业务咨询已经赚得非常丰厚的利润了。以我现在兼职所在的公司来说,就是这样一家软件公司,在行业内积累了足够的领域模型,成立了一个专门的咨询部门,这个部门下面都是咨询师,他们是不管软件开发的,也不懂软件开发,他们就专门教这个行业的客户,教他们怎么去做自己的业务,他们比客户还精通客户的业务,光是业务咨询已经可以为公司带来很多的收入。

 

而软件开发呢?一个并没有行业经验积累的软件公司,它开发的软件,基本上完全是需求驱动,而不是领域模型驱动。只有具备了领域模型积累的公司才有资格去谈领域模型驱动软件开发。在由领域模型往某种编程语言如Java上来实现的时候,绝对不会是1:1的对应关系,即使是粗颗粒度的EJB2模型都做不到,更不要说更加强调细颗粒度的POJO模型呢?用面向对象的语言如Java来编写一个领域模型,如果是用EJB2模型,你需要使用最少两个以上的EJB,即一个 Session Bean,处理面向流程的控制逻辑,一个Entity Bean,处理面向持久化的实体逻辑(持久化操作附着在Entity Bean的Home接口上)。如果是更加复杂的领域模型,那么你需要更多的EJB,也许是一个领域模型需要多个Entity Bean和多个Session Bean。现在我们使用基于POJO模型的实现,那么粗颗粒度的EJB还要继续细分:一个Entity Bean要剥离出来至少三个以上的POJO,即一个或者多个实体类,一个或者多个DAO接口类,一个或者多个DAO接口实现类;一个Session Bean要切分为多个业务Bean。

 

由此我们终于看出来概念是怎样被偷换的了,一个商业概念的抽象领域模型被一个Java持久化实体类替代了。但是我们应该看到,Martin批评的贫血的领域模型并不是Hibernate实体类,Martin指的贫血的领域模型实际上是缺乏丰富业务逻辑概念的领域抽象模型,这和Hibernate实体类完全是风牛马不相及的东西。而Hibernate实体类只是具体编码过程中,为了实现一个领域模型而编写的一组基于POJO的对象中的,完成领域模型某个特征的类。而这个领域模型完整的特征并不应该,也不可能由一个非常粗颗粒度的单类完成,而是由一组互相协作的类完成:即Hibernate的实体类保持领域模型的状态;DAO接口实现类完成领域模型的持久化操作;Spring Bean类完成领域模型的逻辑控制功能。

POJO指的就是非EJB那种重量级,高侵入性的组件模型,关于POJO的定义,你同样可以在Martin Fowler的bliki上面找到。

Spring的Bean是不是POJO? 是的!
Hibernate的entity是不是POJO?是的!
DAO接口是不是POJO?是的!
EJB是不是POJO? 不是的!

我没有看过Martin的DDD,我按照自己的理解, POJO domain models指的就是轻量级的领域模型。何为轻量级? 把领域模型的各个特征,各个属性,各个逻辑都塞到一个class里面叫做轻量级吗?

我认为,Martin批评的贫血的领域模型是指只关注了领域模型持久化特征方面,而忽略了领域模型其他特征方面的模型,这样的模型是贫血的。因为这种模型只关注了模型在技术层面的外在表现,也就是说只关注了数据的存取操作,而忽视了模型蕴含的业务核心价值。

举例来说,我们编一个银行软件,如果你只关注了账户的增删改查,这叫做贫血!而实际上你应该关注的是账户的业务特征,而不是数据特征,你应该关注的是账号开立的业务,账户注销的业务,账号过户的业务等等,这才是领域模型。这种领域模型在一个单纯的技术实现层面来说,对于最简单的业务,你可能只是Account类的增删改查,但是对于复杂的业务来说,他就不单但是一个类,一个表的简单操作了,例如开立账户,你要收手续费,以及考察个人财务状况,那么此时你需要的就是一组协作的类。

Martin提到领域模型,意在强调我们应该关注软件的业务,关注行业知识的内在规律,并且把这种规律建模为领域模型,批评拿到一个软件,脑子里面光想到数据库增删改查的人。这和我们的Hibernate持久化类毫无关系!

我的看法是:一个抽象的领域模型具备多方面的特征,你需要用一组互相协作的类来完成它,每一个或者一组类承担这个领域模型的某个特征。例如某个领域模型,例如上面的账户,你需要一组Hibernate持久化类:包括Account类,User类,Finance类,一组SpringBean类,AccountManager,FinanceManager,一组DAO接口和实现类。由这些POJO的类互相协作来共同完成这个领域模型。如果你仅仅关注Account的增删改查,那就贫血了,而如果你关注了账户的业务规则,并且考虑一组互相协作的类去完成它,就不是贫血的。

窃以为,这是这段时间搜寻的领域模型概念的最合拍的解释了。。

另外还有这两篇

总结一下最近关于domain object以及相关的讨论

再次小结领域模型的种种观点

从技术手段来上说,对于Spring/Hibernate架构,Martin的Rich domin model变得可行了,那么让我们看看究竟有哪些领域模型,以及他们的优缺点:

一、失血模型

失血模型请看 http://forum.javaeye.com/viewtopic.php?t=11712
中列举的第一种模型,简单来说,就是domain object只有属性的getter/setter方法,没有任何业务逻辑。

二、贫血模型

贫血模型请看 http://forum.javaeye.com/viewtopic.php?t=11712
中列举的第二种模型,简单来说,就是domain ojbect包含了不依赖于持久化的领域逻辑,而那些依赖持久化的领域逻辑被分离到Service层。

Service(业务逻辑,事务封装) --> DAO ---> domain object

这种模型的优点:

1、各层单向依赖,结构清楚,易于实现和维护

2、设计简单易行,底层模型非常稳定

这种模型的缺点:

1、domain object的部分比较紧密依赖的持久化domain logic被分离到Service层,显得不够OO

2、Service层过于厚重

三、充血模型

充血模型和第二种模型差不多,所不同的就是如何划分业务逻辑,即认为,绝大多业务逻辑都应该被放在domain object里面(包括持久化逻辑),而Service层应该是很薄的一层,仅仅封装事务和少量逻辑,不和DAO层打交道。
Service(事务封装) ---> domain object <---> DAO

这种模型的优点:

1、更加符合OO的原则

2、Service层很薄,只充当Facade的角色,不和DAO打交道。

这种模型的缺点:

1、DAO和domain object形成了双向依赖,复杂的双向依赖会导致很多潜在的问题。

2、如何划分Service层逻辑和domain层逻辑是非常含混的,在实际项目中,由于设计和开发人员的水平差异,可能导致整个结构的混乱无序。

3、考虑到Service层的事务封装特性,Service层必须对所有的domain object的逻辑提供相应的事务封装方法,其结果就是Service完全重定义一遍所有的domain logic,非常烦琐,而且Service的事务化封装其意义就等于把OO的domain logic转换为过程的Service TransactionScript。该充血模型辛辛苦苦在domain层实现的OO在Service层又变成了过程式,对于Web层程序员的角度来看,和贫血模型没有什么区别了。

四、胀血模型

基于充血模型的第三个缺点,有同学提出,干脆取消Service层,只剩下domain object和DAO两层,在domain object的domain logic上面封装事务。

domain object(事务封装,业务逻辑) <---> DAO

似乎ruby on rails就是这种模型,他甚至把domain object和DAO都合并了。

该模型优点:

1、简化了分层

2、也算符合OO

该模型缺点:

1、很多不是domain logic的service逻辑也被强行放入domain object ,引起了domain ojbect模型的不稳定

2、domain object暴露给web层过多的信息,可能引起意想不到的副作用。

在这四种模型当中,失血模型和胀血模型应该是不被提倡的。而贫血模型和充血模型从技术上来说,都已经是可行的了。但是我个人仍然主张使用贫血模型。其理由:

1、参考充血模型第三个缺点,由于暴露给web层程序拿到的还是Service Transaction Script,对于web层程序员来说,底层OO意义丧失了。

2、参考充血模型第三个缺点,为了事务封装,Service层要给每个domain logic提供一个过程化封装,这对于编程来说,做了多余的工作,非常烦琐。

3、domain object和DAO的双向依赖在做大项目中,考虑到团队成员的水平差异,很容易引入不可预知的潜在bug。

4、如何划分domain logic和service logic的标准是不确定的,往往要根据个人经验,有些人就是觉得某个业务他更加贴近domain,也有人认为这个业务是贴近service的。由于划分标准的不确定性,带来的后果就是实际项目中会产生很多这样的争议和纠纷,不同的人会有不同的划分方法,最后就会造成整个项目的逻辑分层混乱。这不像贫血模型中我提出的按照是否依赖持久化进行划分,这种标准是非常确定的,不会引起争议,因此团队开发中,不会产生此类问题。

5、贫血模型的domain object确实不够rich,但是我们是做项目,不是做研究,好用就行了,管它是不是那么纯的OO呢?其实我不同意firebody认为的贫血模型在设计模型和实现代码中有很大跨越的说法。一个设计模型到实现的时候,你直接得到两个类:一个实体类,一个控制类就行了,没有什么跨越。

这边提到ruby on rails,属于胀血模型,因为它把domain object和DAO都合并了。

窃以为RoR是居于表模块+活动记录,与JAVA适合的情况有些不同。采用活动记录的架构,在持久化的时候,语法貌似更OO些,是直接obj.save()这样,而不是DAO,save(obj)
 
 

Model confusion : Domain Model & E-R Model 前段时间看了DDD,最近在做一个项目的时候Leader要求先出E-R Model,我不是很清楚Domain Model和E-R Model具体的关系和区别。

E-R Model关注的是对象的实体和关系,是Data Modeling的一种方式,建模时并不考虑Entity的行为,在E-R概念模型的基础上可以建立relational data model及physical data model,我不太确认E-R model driven是否就是数据驱动的一种设计流程。

而Domain model driven同样是分析抽象实体并建立实体的关系的过程,同时需要建模实体的职责(对象的行为),以面向对象的手法建立领域层的模型。

我有些迷糊,E-R model driven和Domain model driven 是否是冲突的,或者说可以柔和在一起,比如先建立conceptual e-r model,然后在这个模型的基础上再分别建立relational data model和domain model。但是跟随DDD的分析过程,我实在看不出有建立e-r model的必要,是否可以说,使用了domain driven design就可以不需要e-r model了呢(至少在建立domain model之前)?

 


evan 发表于2005-04-06 11:37 AM  花了点时间去了解了E-R model,domain
model,conceptual model,data modeling的关系与区别,收获颇丰。反过来看,自己之前对这些概念的理解还是比较肤浅的。

首先,需要了解“数据建模”和“对象建模”的概念、关系及区别。在某种层度上两者是具有一定的对立性的,孰幼孰劣即使是专家也众口不一。这里有一篇难得的好贴进行了大量的讨论 数据建模VS对象建模(http://www.hibernate.org.cn/viewtopic.php?t=1464&postdays=0&postorder=asc&start=0)
我们之前两周的工作,大家在概念上的不统一我想很大层度上是因为在这两者的理解上完全还是混淆的而造成的。

我们之前要求设计的E-R Model是属于数据建模的范畴,E-R Model是数据模型的一种表现形式(数据建模不只是E-R Model一种表现形式) ,E-R Model以数据为中心,关注的是对象的实体和关系,建模时并不考虑Entity的行为。在E-R概念模型的基础上可以建立“关系数据模型”进而推导出“物理数据模型”,这是一条以E-R Model为起始的数据建模的路线。 E-R Model的介绍请参看附件 “E-R Model(R).ppt ”。

值得注意的是,在扩展的E-R模型里面具有继承结构,同时以UML的形式也可以表现E-R模型,具体的介绍请参看附件“用UML表示的ER图.pdf”。不过在该领域内的专家Scott.W.Ambler提到"Unfortunately data modeling is not yet covered by the Unified Modeling Language (UML), even though persistence-related issues are clearly an important aspect of object-oriented software project. For several years I have argued that the UML needs a data model (Ambler 1997, Ambler 1997b, Ambler 2001a, Ambler 2002a) and have vacillated between various ways that it should be done."(详见 A UML Profile for Data Modeling http://www.agiledata.org/essays/umlDataModelingProfile.html
这个给我带来了些迷糊,以UML表示的ER图属于数据建模还是对象建模?而这好像正是我们之前两周工作中所面临的问题。

为什么要强调以UML表示的ER图属于数据建模还是对象建模,因为我们之前希望在UML表现的E-R图的基础上建立Domain Model和Relational Data Model,这是否是一条合理的路,或者说在什么情况下合理,我还很难判断。不过Domain Model是属于对象建模的范畴,它和E-R Model的分析具有很大的相似性,最大的区别我认为对象建模需要为对象建立职责(对象的行为),而正因为行为的存在衍生出时序、多态等等对象模型比之数据模型所特有的东西。 从《DDD》的建模分析推导过程,我实在看不出在建立Domain Model之前有建立E-R Model的必要性。但是正如上面帖子里所讨论的,数据建模优先还是对象建模优先,对专家级别的人来说也是由其经验和偏好所决定的。在CMS项目里面,我觉得数据模型上的复杂度并不是很高,我想Domain Model优先可能合适一点。Domain Model到什么地步才会有数据模型或者是关系数据表能确定?我想还是在对象和其属性大致确定的时候比较合适。

最后,我们还提到了概念模型(conceptual model),容易让人混淆的是不管是数据模型还是对象模型都会有 概念的层面。在数据建模中通常将E-R Model就称之为概念数据模型(接下来的层面是关系数据模型和物理数据模型);在对象模型中,对象图通常是从粗到细具有不同的level,可以将只考虑对象实体的划分和关系的建立的层面称之为概念模型(可参考《Analysis Pattern》)

希望若干时间以后我会觉得上面的理解还是很肤浅。

evan 发表于2005-04-06 6:34 PM  和MZhou有一段Mail的交流,以XP和RUP的角度去进行了下区分,希望没有打什么诳语


MZhou:
----------------
Domain Model翻过来是领域模型吧
你需要好好学习学习UML结合RUP过程做项目。因为Rup过程第一大步基本就是领域建模,然后是用例模型,然后是分析模型、对象模型,然后是数据模型。
当然,对于画这几个模型的先后顺序,其实并没有定论,否则RUP就不会那么强调迭代了。当然,对某一个具体的模型,那么肯定是先有领域模型、再有对象模型、再由数据模型。整体项目而言,这些模型就是迭代,项目完快结束了可能还在修改领域模型。

Evan:
--------------------
我的Domain Model是《DDD》里面的概念,我想它和你提到的RUP里面的领域模型应该是有二仪性的,感觉“我的Domain Model”属于对象建模的范畴,“你的领域模型”属于数据建模的范畴(虽然是UML的表现)
我感觉《DDD》在倡导一种XP的风格,而XP本身就颠覆了RUP的很多内容。可能需要同时把这两者都稍微消化消化,才能很好的进行理解和区分,而我,当前正处于消化不良的阶段。


evan 发表于2005-04-07 8:39 AM  think的mail 回复
-------------------------
“领域模型”指的是该模型描述的是现实业务领域,而不是要开发的软件系统中的类。当然,往往现实中的概念会直接映射到系统中。

E/R模型是用数据存储方式来表达领域概念的一种方法,也可以用ER图来表示领域模型。但“数据库建模+编写过程操作数据库”(面向过程)和“用对象封装同源的数据和行为”(面向对象)的思维方法是不一样的,对象方法就是要解决软件的复杂性问题。现代的工具中,数据库的概念模型和物理模型完全可以从类图直接生成,如果采用对像方法,没有必要再去思考ER模型。

Domain model driven说的是如何通过深化领域模型来驱动对业务的理解。

evan 发表于2005-04-07 8:46 AM  在"豆豆他爹"的blog里面看到这样的描述,解惑啊
---------------------------
我不是很清楚你说的PD是什么,是指领域模型(Domain Model)吗? 如果是的话,请看下面我的理解,如果不是,就别看了。
从fdd的资料中,你可以看出,fdd的第1步有两点:1需要domain expert 进行领域走查 2 可以参考用例或者其他形式的需求文档那么,也就是说,fdd关注点是从需求以后的。需求以后的,就是分析和设计啦。

那么我们在看一下你说的业务模型是什么。它是对业务流程中的交互实体的抽象。在rup中,称其为business object model。由于软件系统要对业务流程进行实现(或者进行改进实现),那么业务对象模型也基本会演化成细的计算机模型。在分析阶段的领域模型虽然比业务对象模型细,但还是比设计阶段的领域模型粗点。注意,分析阶段的领域模型,rup中叫分析模型,设计阶段的领域模型,rup中叫设计模型。这就是领域模型由粗到细的精化过程。

在up中,领域模型是一个综合的称谓,包含了业务对象模型,分析模型和设计模型。 领域模型,它的英文是domain model ,而domain,又来源于 problem domain (问题域)这个词组,也就是说,up 对领域模型的命名还是比较准确的。fdd中的领域模型,也可以认为是这个含义。我个人也非常倾向于把这3模型统称为领域模型。因为这样我们的思维才是连续的。

当然,在精化的过程中,有的领域对象会消失或者是分解,这不应影响你对领域模型(这个名字所包含的边界)的理解。


evan 发表于2005-04-07 9:15 AM  Fragment of preface in <<Analysis Pattern>>
-----------------
This is an object-oriented book, and I do not hesitate in proclaiming my belief
that the object-oriented approach is the superior way to develop software. These
models, however, are primarily conceptual models, and many data modelers
have had a long tradition of using conceptual (or logical) models. Data modelers
should find many of the patterns useful, particularly if they use more advanced
semantic techniques. The object-oriented features of the models will reveal many
of the differences between object-oriented and traditional approaches. I would
encourage such readers to use this book in conjunction with an OO analysis book
that stresses the conceptual side of modeling and the links between OO and
semantic data modeling.

evan 发表于2005-04-07 9:19 AM  可见 UML表示的ER图和RUP里面最早分析出的领域模型是不一样的.虽然非常接近,但前者属于数据建模的范畴,后者属于对象建模的范畴.我想,前者易造成混淆,是不值得推荐的

你可能感兴趣的:(领域模型)