什么是领域模型?
领域模型是对领域内的概念类或现实世界中对象的可视化表示。又称概念模型、领域对象模型、分析对象模型。
Domain分两个含义:Domain Object和Domain Service。那么什么样的系统是面向Domain的系统,一个Domain Object和普通的符合OO原则的对象有什么区别;一个Domain Service和普通的Facade或者Manager对象有什么区别。
概念上,一个Domain Object和普通的符合OO原则的对象有声明区别:Domain Object是业务意义上,承载了业务数据(我据此认为所有Domain Object是有状态对象),从本质上说它直接来源于现实世界,没有技术层次上的考虑,“符合OO原则的对象”是用OO方法分析得到的,是基于计算机领域技术的(这样的对象可以是无状态的);但反过来,符合OO的对象不一定反应DOMAIN 的OBJECT。
技术上,Domain Object是指那些包含需要被
透明持久化的属性,以及
相关业务逻辑(体现在
Use Case
中)的
POJO。仔细观察旧的系统,发现Transaction Script还是Table Module操作都的是来自数据库(或者其它持久化通道)的数据,Transaction的业务逻辑是零星片断。而Table Module其操作的是同一类业务数据集合,包含明显的数据库痕迹。而一个Domain Object包含了这些需要被持久化的业务数据,同时还包含了与之相关所有业务操作,并且有自己的继承体系。Martin Fowler认为有了这些就可以称为是一个Domain Object,因此在其PoEAA中的ORM包含了一些不透明的持久化方案。我认为一个真正的Domain Object需要一个透明持久化。
Domain Service包含的商业逻辑包含了两部分:流程逻辑和控制逻辑。
1. 业务领域的
流程逻辑(Business Process)。指一系列的业务行为,包括Domain Object的属性更新;Dao的创建、更新和删除操作以及对Domain Service中的包括Mail,网络等方法的访问。
2. 业务领域的
控制逻辑(Business Rule)。A rule is a declarative statement that applies logic or computation to information values。Business Rule 1. 产生一些控制信息,限制或者触发某些行为的执行;2. 产生一些状态信息,提供给业务人员参考操作。A rule results either in the discovery of new information or a decision about taking action.。
而Facade或者Manager是完全从技术上考虑的,尤其是Facade,通常处理如下逻辑:1. 与表现层通信工作,把表现层的平面数据(VO)转换为相关联的Domain对象,把Domain对象计算的结果转换成平面数据(VO)返回给表现层;2. 根据Use Case完成商业逻辑(面向事务)的调度,包括其业务关联的Domain Object和Domain Service调度,其可能调度了多个Domain Service。在简化的情况下,Facade有时和service可以等同。
如果把一个系统看作是一个Mechanical组件的话,那么Domain Object就是其Structure,相当于人的骨架;而流程逻辑就是Power,相当于骨架上的肌肉;那么控制逻辑就是Control,相当于肌肉中的神经。
为什么要创建领域模型?
降低与OO建模之间的表示差异。
领域层软件类的名称要源于领域模型中的名称,以使对象具有源于领域的信息和职责。
打个比方,你可以用一长串0和1来表示“薪水册”,可是这种软件表示与我们脑中的薪水册领域模型之间存在巨大的差异,这将影响我们对软件的理解和修改。而OO建模则可以减小这一差异。
那又
如何创建领域模型呢?
可以通过以下三个步骤:
一. 寻找概念类
二. 将其绘制为UML类图中的类
三. 添加关联和属性
如何找到概念类?
1)重用和修改现有的模型。
这是
首要、
最佳且
最简单的办法。可以从已发布的领域模型和书籍中获得。
2)使用分类列表
示例:
(图二)
3)确定名词列表
在对
领域的文本性描述中识别名词和名词短语,将其作为候选的概念类或属性。
缺点:自然语言的不精确性,不同名词短语可能表示同一概念类或属性,此外可能还有歧义。
建议与
概念类分类列表一同使用。
在实践中,在发现概念类时,一般直接为其
绘制UML类图。
常见错误:把应该是概念类的事物表示为属性。
准则:
如果我们认为某概念类X不是现实世界中的数字或文本,那么X可能是概念类而不是属性。
考虑一下航空预定领域。destination应该作为Flight的属性,还是作为单独的概念类Airport?
(图三)
在现实世界里,目的地机场不会被看作是数字或文本,而是一占据大规模空间的事物。因此,Airport应该是个概念,而不是属性。
描述类包含描述其他事物的信息。例如,ProductDescription记录Item的价格、图片和文字描述。
为什么使用描述类?
假设:雀巢咖啡,大受欢迎,销售一空。这就意味着雀巢咖啡的所有Item实例都从计算机存储器中被删除。这时如果有人问:雀巢咖啡多少钱一盒?那将没法回答。因为价格是记录在实例上的,而这些实例都已经被删除。由此可以看出,需要其他事物来记录雀巢咖啡的
描述(规格说明)。
(图四)
何时需要?
1. 需要有关商品或服务的描述,独立于任何商品或服务的现有实例。
2. 删除其所描述事物(如Item)的实例后,导致信息丢失,而这些信息是需要维护的,但是被错误地与所删除的事物关联起来。
3. 减少冗余或重复信息。
关联
什么是关联?
关联是类(类的实例)之间的关系,表示有意义和值得关注的连接。
(图五)
何时表示关联?
1. 如果存在需要保持一段时间的关系,将这种语义表示为关联(
“需要记住”的关联)。
2. 从常见关联列表中派生的关联。
准则:
要避免在领域模型中加入太多的关联。
在领域建模过程中,关联不是关于数据流、数据库外键联系、实例变量或软件方案中的对象连接的语句;关联声明的是针对现实领域
从纯概念角度看有意义的关系。
在UML中如何对关联命名?
以“类名-动词短语-类名”的格式为关联命名,其中的动词短语构成了可读的和有意义的顺序。
图五对应于:
VideoStore Stocks Video
多重性定义了类A有多少个实例可以和类B的一个实例关联。(见图五)
多重性的值表示在
特定时刻(而不是在某个时间跨度内)有效关联的实例数量。
(图六)
多重性是和语境有关的。
两个类之间的多重关联:
(图七)
常见关联列表:
(图八)
属性
什么是属性?
属性是对象的逻辑数据值。
何时展示属性?
当需求(例如,用例)建议或暗示
需要记住信息时,引入属性。
(图九)
导出属性(derived attribute):可以由其他信息导出的属性。
准则:
大部分属性类型应该是“简单”数据类型,例如数字和布尔。通常,
属性的类型不应该是复杂的领域概念,例如Sale或AirPort。
准则:
领域模型中属性的类型更应该是数据类型。
准则:
通过关联而不是属性来表示概念类之间的关系。
(图十)
领域模型是概念透视图,不是软件透视图。在设计模型中,属性可以是任何类型。
准则:任何属性都不表示外键。
(图十一)
结论:
没有所谓唯一正确的领域模型。所有模型都是对我们试图要理解的领域的近似。领域模型主要是在特定群体中用于理解和沟通的工具。有效的领域模型捕获了当前需求语境下的本质抽象和理解领域所需要的信息,并且可以帮助人们理解领域的概念、术语和关系。