`
rq2_79
  • 浏览: 240489 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

领域模型的设计问题

阅读更多

关于领域模型的设计问题,JavaEye已经组织过n多次大规模讨论,几乎每过一段时期就会出现一次。最近出现了一个新的趋势,Craig Walls在自己的blog上面写一篇文章,介绍如何使用Spring2.0AspectJ的新特性给domain object注入DAO依赖,即如何实现post-instantiation,请见:
http://jroller.com/page/habuma?entry=spring_2_0_vs_the

与此同时,ajoo也给出了nutspost-instantiation方案,请见:
http://www.iteye.com/display/ajoo/Dependency+Injection+For+Rich+Domain+Model

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


一、失血模型

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

二、贫血模型

贫血模型请看
http://forum.iteye.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

http://robbin.iteye.com/blog/17579?page=1#comments

这种模型的优点:
1
、更加符合OO的原则
2
Service层很薄,只充当Facade的角色,不和DAO打交道。 这种模型的缺点:
1
DAOdomain object形成了双向依赖,复杂的双向依赖会导致很多潜在的问题。
2
、如何划分Service层逻辑和domain层逻辑是非常含混的,在实际项目中,由于设计和开发人员的水平差异,可能导致整个结构的混乱无序。
3
、考虑到Service层的事务封装特性,Service层必须对所有的domain object的逻辑提供相应的事务封装方法,其结果就是Service完全重定义一遍所有的domain logic,非常烦琐,而且Service的事务化封装其意义就等于把OOdomain logic转换为过程的Service TransactionScript。该充血模型辛辛苦苦在domain层实现的OOService层又变成了过程式,对于Web层程序员的角度来看,和贫血模型没有什么区别了。

四、胀血模型 基于充血模型的第三个缺点,有同学提出,干脆取消Service层,只剩下domain objectDAO两层,在domain objectdomain logic上面封装事务。
domain object(
事务封装,业务逻辑) <---> DAO 似乎ruby on rails就是这种模型,他甚至把domain objectDAO都合并了。 该模型优点:
1
、简化了分层
2
、也算符合OO 该模型缺点:
1
、很多不是domain logicservice逻辑也被强行放入domain object ,引起了domain ojbect模型的不稳定
2
domain object暴露给web层过多的信息,可能引起意想不到的副作用。

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

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

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

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

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

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

关于领域模型的问题,限于时间原因,暂时不能展开详谈,待有空,写篇更加详细的文章。

分享到:
评论
1 楼 rq2_79 2008-02-28  
领域模型的概念
自从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的增删改查,那就贫血了,而如果你关注了账户的业务规则,并且考虑一组互相协作的类去完成它,就不是贫血的。

相关推荐

    领域驱动模型(DDD).zip_ddd_领域模型_领域驱动_领域驱动设计

    战略设计关注如何将大系统划分为更小、更自治的领域,每个领域都有自己的领域模型,如子域划分、限界上下文等。战术设计则关注如何在每个领域内构建模型,包括实体、值对象、工厂、仓储、聚合根等设计模式。 在实践...

    DDD领域模型设计方案

    通过以上介绍,我们可以看到DDD领域模型设计方案是围绕业务领域进行的深度建模,旨在提高软件的业务契合度和灵活性。菱形对称架构则为这种建模提供了一个清晰的组织结构,帮助开发者更好地理解和管理复杂的系统。在...

    领域模型驱动设计1553265830.pdf

    - 领域模型设计:采用充血模型而非贫血模型,并且在设计中融合设计模式、流程编排、事件驱动等元素。 - 强化单测:确保代码的质量,通过单元测试来保证各个领域模型的正确性和稳定性。 - 持续重构:在业务生命周期内...

    架构设计中领域模型设计思路

    本文将深入探讨领域模型设计的思路,结合给定的文件名,我们可以推测这是一个与网络通信或者消息处理相关的系统,涉及到数据包的解析和业务处理。 首先,领域模型的设计应该基于业务需求,它应包含业务领域的核心...

    lec-5 领域模型 DomainModel.ppt

    领域模型是软件设计中的一种重要概念,它旨在理解系统如何工作,包括内部行为和外部行为。领域模型的目的是为了确定系统中各个元素之间的交互关系,以便产生外部行为。 领域模型为什么重要?因为它可以帮助我们理解...

    领域驱动设计C# 2008实现问题.设计.解决方案

    3.2.1 设计领域模型 3.2.2 定义项目聚合 3.2.3 定义聚合边界 3.2.4 设计仓储 3.2.5 编写单元测试 3.3 解决方案 3.3.1 project类 3.3.2 实现仓储 3.3.3 实现服务类 3.3.4 实现项目信息视图模型 3.3.5 实现...

    领域驱动模型设计和应用

    在“领域模型应用.doc”和“领域驱动设计.doc”中,你将找到更具体的案例分析和详细设计步骤,帮助你进一步理解如何在实际项目中应用DDD。通过这些文档,你将能够学习如何将业务知识转化为代码,构建出符合业务逻辑...

    使用领域模型构建UML类模型

    "使用领域模型构建UML类模型" 领域模型是软件开发中的一种重要技术,它能够捕获系统语境中最重要的对象类型,使...因此,领域模型在软件开发中的作用非常重要,开发人员应该充分利用领域模型来提高系统的设计和实现。

    Java领域模型驱动设计案例

    什么是领域(Domain)? 我们所做的软件系统的目的都是来解决一系列问题,例如...通常我们说,要成为一个领域的专家,必须要在这个领域深入研究很多年才行,只有这样才会遇到非常多的该领域的问题,积累了丰富的经验。

    领域模型最近代码实现

    领域模型是软件开发中的一个重要概念,特别是在面向对象设计和领域驱动设计(DDD)中。它是一种将业务领域的概念、规则和行为转化为计算机程序的方式。在本文中,我们将深入探讨领域模型的理论基础,以及如何在实际...

    领域驱动设计与模型驱动开发

    这些构造块是设计和实现领域模型的基本元素,通过它们可以构建一个逻辑清晰、结构层次分明的领域模型。 领域驱动设计的编程实践强调了面向对象分析与设计技术的重要性,它对技术框架进行分层规划,如用户界面/展现...

    领域模型设计详细举例.pdf

    领域模型设计详细举例.pdf领域模型设计详细举例.pdf领域模型设计详细举例.pdf领域模型设计详细举例.pdf领域模型设计详细举例.pdf领域模型设计详细举例.pdf

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

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

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

    领域模型(Domain Model)和贫血模型(Anemic Domain Model)是两种常见的模型设计模式,它们各有特点,适用于不同的场景。本资料包旨在通过实例对比,帮助初学者理解这两种模型的区别和概念,并提供实际的Java代码...

    Rafy领域实体框架-领域模型设计器设计方案.docx

    领域模型设计器是Rafy框架的一个重要组成部分,旨在提供一个直观的工具,帮助开发者和非开发人员理解、查看和设计领域模型。设计的目标包括三个方面: 1. 外部简单设计器:作为一个独立运行的软件,它可以打开和...

    DDD领域设计模式代码案例

    通过学习这个DDD案例,开发者可以更深入地理解如何在实际项目中应用DDD,包括如何定义领域模型,如何组织业务逻辑,以及如何设计和实现与数据库的交互。这对于提升软件开发的效率和质量,特别是面对复杂业务场景时,...

    大白话领域驱动设计DDD视频教程

    第3章 领域设计模型 实体和值对象? 贫血模型的优缺点? DDD提倡的充血模型是什么? 体会下充血模型开发微信钱包系统 聚合和聚合根是什么? 领域事件是什么? 看看领域事件的本质(解耦,异步,削峰) 工厂和资源库的...

    领域模型项目示例

    在IT行业中,领域模型(Domain Model)是一种重要的软件设计概念,尤其在企业级应用开发中占据核心地位。领域模型是对业务领域的抽象和简化,它包含了业务规则、业务实体以及它们之间的关系。本项目示例旨在提供一个...

    DDD领域驱动设计学习框架简介PPT

    DDD则侧重于设计范畴,它关注如何通过领域模型来组织和管理代码,使软件更好地反映业务逻辑。 软件开发的本质可以理解为将现实世界的问题转化为计算机世界的解决方案。在这个过程中,DDD提供了一种结构化的方法,...

Global site tag (gtag.js) - Google Analytics