`

领域模型的概念

 
阅读更多

 

自从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)

分享到:
评论

相关推荐

    贫血模型or领域模型

    贫血模型or领域模型的举例对比,让你初步了解贫血模型与领域模型的区别和概念

    领域模型说明及范例代码.zip

    贫血模型or领域模型的举例对比,让你初步了解贫血模型与领域模型的区别和概念。附加一个自己创建的代码范例

    [领域驱动设计:软件核心复杂性应对之道].Eric.Evans.扫描版(ED2000.COM)

    过去系统分析和系统设计都是分离的,正如我们国家“系统分析师” 和“系统设计师” 两种职称考试一样,这样... DDD则打破了这种隔阂,提出了领域模型概念,统一了分析和设计编程,使得软件能够更灵活快速跟随需求变化

    如何设计架构-分层和组织领域模型

    如何设计架构-分层和组织领域模型 层(layer)这个概念在计算机领域是非常了不得的一个概念。计算机本身就体现了一种层的概念:系统调用层、设备驱动层、操作系统层、CPU指令集。每个层都负责自己的职责。 要组织...

    UML 格子店概念模型

    UP中将其定义为,领域模型是对现实世界概念类的表示;是可以在业务建模科目中创建的制品之一。在应用UML表示法,领域模型被描述未一组没有定义操作的类图,它包括3个要素,分别是概念,关联,属性。

    领域模型(概念类图)页PPT文档

    领域模型(概念类图)页PPT文档 1、概念模型的简介 2、建立概念模型的基本步骤

    领域模型和微服务的关系

    微服务架构首先要关注的不是RPC/ServiceDiscovery/Circuit Breaker这些概念,也不是Eureka/Docker/SpringCloud/Zipkin这些技术框架,而是服务的边界、职责划分,划分错误就会陷入大量的服务...• 充血模型 • 事件驱动

    论文研究-电子对抗作战模拟领域概念模型设计研究.pdf

    基于领域模型重用机制,以提高模型重用性为目标,分析了领域概念模型体系结构的设计方法,将概念模型体系分为军事概念模型、逻辑概念模型和领域专业术语字典三个部分。介绍了构建领域概念模型的设计流程和关键技术,...

    基于领域知识模型的突发事件智能信息检索系统研究

    基于领域知识模型的突发事件智能信息检索系统研究 人工智能

    通用大模型与垂直大模型详细介绍

    【内容概要】主要包含如下几个方面的内容。 引言 通用大模型概述 垂直大模型概述 通用大模型与垂直大模型比较...·本文重点介绍通用大模型与垂直大模型的基本概念、特点及应用领域,帮助读者全面了解和认识这两种模型。

    浅谈领域模型

    一般意义上的领域模型是面向软件工程领域的,而现实意义的领域模型则包含了商业模式等广义上的概念。很多人一上来理解领域驱动设计(DDD),基本都是一头雾水,因为模型设计的初衷并不是围绕性能、架构、分层等软件...

    领域模型学习笔记

    领域模型是对领域内的概念类或现实世界中对象的可视化表示。又称概念模型、领域对象模型、分析对象模型。那什么是概念类呢?概念类是思想、事物或对象。这样的解释,仍然显得抽象。还是先看图吧!(图一)利用上图,...

    论文研究-利用领域本体概念关系的混合信息检索方法.pdf

    利用领域本体概念关系实现语义检索,当没有可用的本体知识时,按传统关键词匹配完成检索。这种基于领域本体的混合信息检索模型融合关键词检索和语义检索的优势,弥补各自的不足,以改善检索性能。将其应用于计算机...

    论文研究-基于LDA的领域本体概念获取方法研究.pdf

    以文本信息作为数据源,采用NLPIR自适应分词与过滤方法获取候选术语集,设计了领域本体的LDA主题模型,通过吉布斯采样进行LDA模型训练与主题推断,实现了领域本体核心概念的相关术语提取;基于LDA主题概率分布研究了...

    《UML和模式应用》之领域模型

    领域模型:是对领域内的概念类或现实世界中对象的可视化表示[MO95,Fowler96]。领域模型也称为概念模型,领域对象模型和分析对象模型。UP对领域模型的定义是,可以在业务建模科目中创建的制品之一。更准确地讲,UP...

    SysML系统模型与机械领域的集成

    本文参考对SysML及MBSE概念体系理解的基础上,结合几种不同的场景,解释了系统模型如何与机械领域(CAD模型)进行集成,期望通过此文章,对读者正确理解MBSE概念和指导企业实践MBSE能有所借鉴。 基于模型的系统工程...

    论文研究-气象服务形式概念分析模型研究.pdf

    为了解决气象服务领域隐含知识难以发现、概念处理不够准确的问题,在形式概念分析理论指导下,给出气象服务领域知识发现和表示模型。以互联网联盟(W3C)OWL2描述逻辑本体知识库应用为背景,提出使用一阶谓词定义多...

    一个简单例子:贫血模型or领域模型

    问题是大家对贫血模型和领域模型都有自己的看法,如果没有对此达到概念上的共识,那么讨论的结果应该可想而知,讨论的收获也是有的,至少知道了分歧的存在。为了使问题具有确定性,我想从一个简单例子着手,用我对...

    DDD领域驱动设计_领域驱动设计_twice9t6_

    DDD打破了这种隔阂,提出了领域模型概念,统一了分析和设计编程,使得软件能够更灵活快速跟随需求变化。见下面DDD与传统CRUD或过程脚本或者面向数据表等在开发效率上比较

Global site tag (gtag.js) - Google Analytics