业务对象模型(也叫领域模型)是描述业务用例实现的对象模型。它是对业务角色和业务实体之间应该如何联系和协作以执行业务的一种抽象。

      业务对象模型从业务角色内部的观点定义了业务用例。该模型为产生预期效果确定了业务人员以及他们处理和使用的对象(“业务类和对象”)之间应该具有的静态和动态关系。它注重业务中承担的角色及其当前职责。这些模型类的对象组合在一起可以执行所有的业务用例。

一、业务对象模型(领域模型)的核心元素

      业务角色显示了一个人承担的一系列职责。
      业务实体表示使用或产生的可交付工件、资源和事件。
      业务用例实现显示了协作的业务角色和业务实体如何执行某个工作流程。使用以下几种图来记录业务用例实现:
          图显示参与的业务角色和业务实体。
          活动图,其中泳道显示业务角色的职责,而对象流显示如何在工作流程中使用业务实体。
          序列图描述业务角色和业务主角之间交互的详细情况,并显示如何在业务用例执行过程中访问业务实体。

      业务对象模型将结构的概念和行为的概念结合了起来。

      它是一个纽带工件,用于对业务关系进行清晰的表述,表述方式与软件开发人员的思考方式类似,同时仍保留一些纯粹的业务内容。将我们所知道的有关业务的信息按照对象、属性和职责进行了合并。

      它探索业务领域知识的本质,所采用的方式使我们能够从对业务问题的思考转变到对软件应用程序的思考上来。

      它是一种确定需求的方法,使需求能够为待建信息系统使用,并得到该系统的支持。

      确定业务对象定义、对象间关系、对象名称和对象间关系名称的流程使我们能够以一种能被业务领域专家理解和验证的精确方式来表达业务领域知识。

二、如何命名业务角色和业务实体

      对每个业务角色和实体进行命名,要求名称能够表示对象的职责。

      一个好的名称通常是名词或动词的名词形式。
      每个名称都必须是唯一的。
      避免使用发音或拼写类似的词以及同义词作为名称。
      可能需要用好几个单词来组成一个明确的、无需额外说明的名称。

三、涉及业务用例的业务对象

      当您研究参与业务中不同用例的业务角色和业务实体时,可能会发现某些对象如此相似,以致于实际上是一个类。即使不同的业务用例没有相同的要求,类之间也可能相似到足以被视为一个相同现象的程度。如果是这种情况,您应该将相似的类合并在一起。这就产生了一个业务角色或业务实体,它拥有足以满足不同业务用例要求的关系、属性和操作。

      因此,多个业务用例可以对同一个类有不同的要求。对于业务角色来说,如果有些雇员有能力担当所描述的一组角色,那么同样还要有一些比较灵活可以胜任多个职位的雇员。这会使您的业务更加灵活。

四、业务对象模型和信息系统

      在业务对象模型中,业务角色代表雇员将担当的角色,而业务实体则代表雇员将处理的对象。一方面,可以使用业务对象模型来确定业务雇员将如何进行交互,以产生业务主角所期望的结果。另一方面,系统用例模型和设计模型指定了业务的信息系统。

      业务建模和系统建模解决不同的问题,其抽象程度也不一样。所以一般而言,信息系统不应该直接出现在业务模型中。

      另一方面,雇员作为业务角色来使用信息系统,实现相互之间的通信、与主角的通信以及对业务实体信息进行访问。所有的链接、关联关系或属性都有某个潜在的信息系统对其进行支持。

      这两类建模环境有以下关系:

      作为特定业务角色的雇员与信息系统的一个系统主角相对应。如果建立的信息系统使该雇员在业务用例中的所有工作都得到一个系统用例的支持,则他最有可能得到最好的支持。
      另外,如果业务用例规模大、生存期长或者合并了多个独立领域中的工作,信息系统用例将可以支持业务角色的操作。
      雇员工作的对象(建模为业务实体)常在信息系统中得到表现。在信息系统的对象模型中,这些业务实体作为实体类出现。
      业务实体之间的关联关系和聚合关系常常使设计模型中实体类之间产生对应的关联关系和聚合关系。
      因此,系统用例访问并操作设计模型中的实体类,这些实体类代表由被支持业务用例访问的业务实体。
      最后,直接使用业务信息系统的业务主角也成为信息系统的系统主角。
 
      当确定对支持业务的信息系统的需求时,这些关系十分关键。

五、作为业务主角的信息系统

      有时候,一个业务的雇员与另一个业务的雇员使用其他业务的信息系统进行联系。从建模后业务的角度来看,这个信息系统就是一个业务主角。

      示例:
      某个软件开发人员努力去理解他所负责的产品中出现的问题。为了了解问题是否源于他所使用的编程工具,他与供应商的万维网服务器联系,并仔细研究编程工具当前版本中已知问题的列表。通过这种方式,业务角色“软件开发人员”与业务角色“提供商的万维网服务器”进行交互。

六、在业务对象模型中明确建模的信息系统

      通常的做法是不在业务对象模型中对信息系统进行明确建模,因为信息系统只是业务角色所使用的工具而已。但当业务的信息系统被客户直接使用时,这种做法就不合适了。如果这个交互是业务服务的主要部分,您可能会出于商业上重要性的考虑而希望在业务对象模型中将其展示出来。电话银行业务就是此类信息系统的一个很好的例子。

      从业务建模的观点来看,建议使用以下方法:

      将信息系统看做一个和主角交互的完全自动化的业务角色。
      如果信息系统和任何其他业务角色或业务实体相关,则考虑使用链接或关联关系来说明这种关系。系统可能会向某个业务角色通知其进度,或者使用与某个业务实体相关的信息。
      简单地说明业务角色,同时列出代表业务对象模型中信息系统的服务。
      在信息系统模型中对信息系统和其环境的所有细节和特征进行建模。
      引入一个命名约定,这样可以容易地在业务角色中确定那些完全自动化的业务角色,例如,一个前缀或后缀,如“自动<业务角色名称>”或“<业务角色名称>(IT 系统)”。您甚至可以使用一个特殊的图标来定义构造型。
 
七、好的业务对象模型的特征

      总的来看,业务角色和业务实体执行业务用例中描述的所有活动,绝不多一点,也绝不少一点。
      业务对象模型有效、全面地对组织进行了展示。 (来源:Rational Software Corp.)

 

 


领域模型的概念




自从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以及相关的讨论

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


 

 

 


 

这边提到ruby on rails,属于胀血模型,因为它把domain object和DAO都合并了。
窃以为RoR是居于表模块+活动记录,与JAVA适合的情况有些不同。采用活动记录的架构,在持久化的时候,语法貌似更OO些,是直接obj.save()这样,而不是DAO,save(obj)

 

 

 


 

从技术手段来上说,对于Spring/Hibernate架构,Martin的Rich 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

这种模型的优点:
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认为的贫血模型在设计模型和实现代码中有很大跨越的说法。一个设计模型到实现的时候,你直接得到两个类:一个实体类,一个控制类就行了,没有什么跨越。