领域建模

  作者:久隆信息 张晓刚
2009/10/22 11:34:20
使用领域模型描述一个领域的所有对象和他们的关系。领域模型可以捕捉一个系统内,组织内或者任何特定领域的重要对象。

我们常说“使用领域模型来描述了一个领域的所有对象和他们的关系。领域模型可以捕捉一个系统内,组织内或者任何特定领域的重要对象。”

但是领域模型绝不是一堆带有getter和setter的POJO对象。在说明这个问题之前,我们需要先回答一个问题,什么是领域模型?

对于“模型”这个词语来说,很容易理解。模型是一种简化,它对现实进行阐述,只是抽象出来与解决手头问题有关的方面而忽略掉无关的细节问题。

每个软件程序都会跟其用户的活动或者兴趣有关,用户在其中使用程序的主要环境被我们称为软件的领域。领域可能会涉及到具体的世界,航班预订程序的领域涉及到登机人,ATM取款涉及到银行账户。

我们开发软件的目标是建立对用户活动有价值的软件,开发团队必须瞄准与这些活动有关的知识主体。对开发人员所要求的知识可能是令人望而生畏的,模型正式这样一种东西,帮助开发人员处理这些信息与知识。一个合适的模型能够让人了解信息的含义并且聚焦于问题本身。

Martin Fowler在P of EAA中阐述过,”domain model is an object model of the domain that incorporates both behavior and data”。

注意“behavior and data”。事实上,不止一个人这样认为,Eric Evans在DDD中写到:

Domain Layer (or Model Layer): Responsible for representing concepts of the business, information about the business situation, and business rules. State that reflects the business situation is controlled and used here, even though the technical details of storing it are delegated to the infrastructure. This layer is the heart of business software.(领域层负责表示业务概念,业务状况的信息以及业务规则,尽管保存这些内容的技术细节由基础架构层完,反映业务状况的状态在该层中被控制和使用,这一层是业务软件的核心。)

好了,我想我们已经说的够清楚了。

领域模型是一个高层次的概念模型。一般来说

1) 概念类使用“Class”元素来描述;

2) 每一个概念类包括“属性”和“操作”;

3) 概念模型可以与其他概念模型或者自己本身有关联;

我们现在一谈领域模型,很多人脑子里就想到数据库增删改查。实际上这也就是很多人批评的。贫血的领域模型只关注领域模型的持久化特征方面,而忽略了领域模型其他特征方面的模型,这样的模型是贫血的。因为这种模型只关注了模型在技术层面的外在表现,也就是说只关注了数据的存取操作而忽略了模型蕴含的业务核心价值。

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

再举一个例子。员工入职,员工入职以后需要在HR系统中建立基本档案,完成雇佣操作后,需要信息管理部门分配分机、客户端IP,这些信息又返回到HR系统中。
JAVA EYE上有段时间对领域模型进行了热烈的讨论,具体讨论不做描述,详细的可以去看相关的论坛。

Robbin对三种模型贫血、充血、涨血做了总结,这里参考一下

第一种模型:只有getter/setter方法的纯数据类,所有的业务逻辑完全由business object来完成(又称TransactionScript),这种模型下的domain object被Martin Fowler称之为“贫血的domain object”

第二种模型,是Martin Fowler指的rich domain object

第三种模型:所有的业务逻辑在领域模型中实现。

还是用他的一个例子来说明问题,领域模型该如何设计

一个简单的公司工时管理系统,记录员工的个人信息,每个员工的工作任务分配,以及工作所属类别(例如开发,还是测试,还是培训等等),其中每个员工有n个 任务,员工和任务是一对多关系,每个员工也分别隶属于多个不同的工作类别,员工和类型是多对多关联关系,而每个任务也分别隶属于唯一的工作类别,任务和类 别是多对一关系。另外系统不要求对部门信息进行维护,不需要department表。因此,在这个系统中使用四张数据库表:

users表保存员工信息,有name, password, gender, department, salary

tasks表保存工作任务信息,有name,start_time, end_time

kinds表保存工作所属类别,有name

kinds_users表是一张关联表,保存users表和kinds表的多对多关联外键的

系统的功能需求如下:

1、某部门录用一名新员工

2、某部门员工总薪水总和

3、某员工已经开始但尚未结束的任务

4、给某员工分配一项任务

5、所有用户当前已经开始但尚未结束的任务

6、对某一类别,给所有和此一类别相关的员工,批量新增一批任务

7、针对任务的统计功能,给定某类别,统计当月总的任务数,已完成任务数,未完成任务数
 

按照第一种模型的设计是什么样的呢?要的到部门内员工的薪水总和,这个业务方法多数是在一个业务逻辑类里面,可能叫做SalaryService.getSalaryByDept()。
这样当然不会有什么问题,程序一样执行,因为大多数开发人员,多数的软件公司都是这么干的,长久以来很多人的习惯就是这样。但是这种做法最大的问题就是把跟持久化无关的业务逻辑从领域模型剥离掉了,领域模型脱离了持久层或者业务逻辑层之后时候还能重用?核心的业务逻辑已经没了。当然有人可能会说,即使用第二种模型,领域模型也不能完全具有所有的业务逻辑,这是另外一个话题,不是我们要说的如何进行领域模型的设计。

这里提到这个例子的目的是说我们做领域模型分析的重点是什么?领域模型的属性么?这也是很多人经常遇到问题,忘记了领域模型的行为。领域模型不是一堆实体对象的关系,需要包含的重要的业务逻辑信息。业务逻辑放到哪里去,是另外的需要讨论。

我们来看这样一个图:

这个图描述的信息跟我们最终的实现肯定会有很大的差异,因为这不是我们最终的实现类,因此你可能把逻辑放在domain object中,也可能把逻辑放在domain service中。但是这个图清楚的描述了每一个领域对象所包含的信息及其行为。可能在你的项目你会使用贫血模型,可能你会使用充血模型,这不是重要的,因为专家也不一定是对的(Martin Fowler在PoEAA中认为,越是企业应用的复杂业务逻辑,Rich domain model架构越合适,对于简单企业应用,贫血模型也不错,但是他认为随着业务逻辑复杂度上升,贫血模型的弊端会被放大,变得开始不合适了。)。

写到这里,其实大家看明白了,一堆的废话,只是告诉你领域建模的时候别忘记了行为。呵呵。

共2页: 上一页1 [2]
责编:张赛静
vsharing微信扫一扫实时了解行业动态
portalart微信扫一扫分享本文给好友

著作权声明:畅享网文章著作权分属畅享网、网友和合作伙伴,部分非原创文章作者信息可能有所缺失,如需补充或修改请与我们联系,工作人员会在1个工作日内配合处理。
最新专题
成都行

成都行亮点 成都行程 智囊团 参观成员 合作媒体 活动咨询..

2015年中国制造业信息化峰会

大会聚焦 大会亮点 大会议程 重要嘉宾 成都行 赞助合作 ..

    畅享
    首页
    返回
    顶部
    ×
      信息化规划
      IT总包
      供应商选型
      IT监理
      开发维护外包
      评估维权
    客服电话
    400-698-9918