领域模型的精化
目标:
- 使用泛化、特化、关联类、时间间隔、组合和包等概念精化领域模型。
- 确定在何时表示子类才具有价值。
泛化和特化是领域建模中支持简练表达的基本概念;更进一步讲,概念类的层次结构经常成为激发软件类层次结构涉及的灵感源泉。软件类层次结构涉及利用继承机制减少了代码的重复。关联类捕获关联关系自身的信息。时间讲反映了某些业务对象仅在有限的一段时间内有效这一概念。使用包可以讲大的领域模型组织成较小的单元。大部分概念将在NextGen案例研究的语境中进行介绍。
NextGen 领域模型中的新概念
同在迭代1中一样,通过反复研究本阶段需求中的概念,逐步增量地开发领域模型。诸如概念分类李彪、名词短语识别这样的技术对开发领域模型会有所帮助。研究讨论这一主题的其他作者的著作是开发健壮、丰富的领域模型的有效途径。
概念分类列表
从用例中识别名词短语
需要反复提醒,名词短语是恶技术不能机械地永远识别领域模型中的有关概念。由于自然语言具有歧义性,文本中的有关概念不会总是显示存在,必要的判断和适当的抽象是必要的。尽管如此,名词短语识别技术由于简单移动,依然是领域建模方面很实用的技术。
授权服务的事务
通过名词短语识别技术可以揭示诸如CreditPaymengRequest、CreditApprovalReply这样的概念。事实上,这些giant可以看作与外部无法的某种类型的事物。识别这些事物很有用处,业务各种活动和过程往往与事务活动相关。
这些事物不一定需要表示为计算机记录或字节流。它们表现了对事务的抽象,而与其执行的含义无关。
泛化
CashPaymeng、CreditPayment、CheckPaymeng这些giant很相似。在这种情形下,可能和有用的方法是将它们组织成泛化-特化类层次结构,其中超类Paymeng表示更为普通的概念,子类表示更为特殊的概念。
注意本章讨论的类是概念类,而不是软件类。
泛化是在多个概念中识别共性和定义超类与子类关系的活动。此活动对概念进行分类学意义上的分类,并将其在类层次结构中表示出来。
在领域模型中识别父类和子类是一个有价值的活动,这样可以使我们对概念有更概括、精炼和抽象的描述。它可以精简表示、改善理解、减少重复信息。尽管我们现在关注UP领域模型,而不是软件涉及模型,但软件设计模型设计和实用继承将超类和子类实现为软件类也会得到更好的软件质量。
识别领域中与本次迭代有关的超类和子类,并且在领域模型中阐明。
定义钙奶超类和子类
既然是被概念超类和子类具有价值,那么就类的定义和类集而言,清晰、准确地理解泛化、超类、子类将非常帮助。
泛化和概念类的定义
概念超类和子类之间使什么关系?
概念超类的定义较子类的定义更为概括或包含范围更广。
泛化和类集
就集合的成员关系而言,概念子类和超类具有相关性
概念子类集合的所欲成员都是其超类集合的成员。
概念子类定义的一致性
当创建一个类层次结构后,有关超类的陈述都适用于子类。
概念超类的定义必须100%适用于子类。子类必须100%与超类一致:属性和关联。
概念子类集合的一致性
概念子类应该使超类集合的一个成员。
子类集合的所有成员必须是其超类集合的成员。
实用自然语言,通常可以通过构造下面的陈述语境进行非正式的测试:子类是一种(is-a)超类。
什么是正确的概念子类
潜在的子类应遵守以下规则:
- 100%规则(定义的一致性)
- Is-a规则(集合成员关系的一致性)
何时定义概念子类
应该何时定义子类呢?首先引入一个定义:概念类的花费是指将一个概念类划分为几个不相交的子类。
将概念类划分为子类的动机
在下述几种情形下创建概念类的子类:
- 子类有额外的有意义的属性。
- 子类有额外的有意义的关联。
- 子类概念的操作、处理、反应或实用的方式不同于其超类或其他子类,而这些方式是我们所关注的。
- 子类概念表示了一个活动提,其行为与超类或者其他子类不同,而这些行为是我们所关注的。
何时定义概念超类
通常在识别出潜在子类的共性时,将其泛化为公共的超类。下面时泛化和定义超类的动机:
- 潜在的概念子类表示的时相似概念的不同变体。
- 子类满足100%和Is-a规则。
- 所有子类都具有相同的属性,可以将其解析出来并在超类中表达。
- 所有子类都具有相同的关联,可以将其解析出来并与超类关联。
NextGen POS案例中的概念类层次结构
Payment类
授权服务类
授权事物处理类
抽象概念类
在领域模型中识别抽象类时有用的,因为它们可以限制哪一些类可以拥有具体实例,从而澄清了问题领域的规则。
如果类C的每个成员也必须时某个子类的成员,则类C被称为抽象概念类。
对变化的状态建模
不要将概念X的状态建模未X的子类。有两个办法可供选择:
- 定义状态类层次结构,并将其与类X关联。
- 在领域模型中忽略概念的状态,而在状态图中加以反映。
软件中的类层次结构和继承关系
因为这里的讨论时关注领域模型的概念观点,而非软件对象,因此关于概念类层次结构的这个讨论并未提及继承关系。采用一种面向对象语言,通过创建软件类层次结构,软件子类继承超类的苏醒和操作定义。继承是使超类的特性适应于子类的软件机制,它支持对子类代码的重构,将其置入超类之中,形成类层次结构。因此,在领域模型中讨论继承美誉意义,而当我们转向设计和实现视图时它才具有重要意义。
这里所产生的概念类层次结构未必会反映在设计模型中。这取决于编程语言特性和其他因素。
关联类
在领域模型中,如果类C可能同时有多个相同的属性A,则不要将属性A置于C之中。应该将属性A放在另一个类中,并且将其与类C关联。
在领域模型中增加关联类的可能线索有:
- 有某个属性与关联相关。
- 关联类的实例具有依赖于关联的生命期。
- 两个概念之间有多对多挂了,并且存在与关联自身相关的信息。
多对多关联的存在是实用关联类的最常见线索。当你见到多对多关联,则需要考虑实用关联类。
聚合关系和组合关系
不要在UML中飞信去实用聚合;而且,在适当的时候使用组合。
组合是一种很强的整体-部分聚合关系,并且在某些模型中具有效用。
如何识别组合关系
在某些情形中,通常是在物理组装中,识别组合关系很容易。但有时,组合关系并不明显。关于组合关系:如有疑问,扔在一边。
在下述情形下,可以考虑组合关系:
- 部分的生命周期在组成的生命周期界限之内,部分的创建和删除依赖于整体。
- 在物理或逻辑组装上,整体-部分关系很明确。
- 组成的某些属性会传递给部分。
- 对组成的操作可能传递给部分。
显示组合关系的益处
识别和显示组合关系并不是非常重要的;在领域模型中排除组合关系也是合乎情理的。大部分有经验的领域建模者都发现人们对这些关联关系进行了太多无益的正乱。
由于有以下益处,因此发现和现实组合关系还是很有用的,泽泻优点中的大部分都与设计而非分析活动相关,这也是从领域模型中排除组合关系没有太大影响的原因:
- 有利于澄清部分对整体依赖的领域约束
- 有助于使用GRASP创建者模式时识别创建者
- 对整体的辅助、拷贝这些操作经常ui传递给部分。
NextGen领域模型中的组合关系
时间间隔和产品价格-解决迭代1阶段的“错误”
关联角色名称
在关联的每一端都是一个角色,角色有各种属性,例如:名称和多重性。
uese名称在关联末端加以表示,并很好地描述出对象在关联中所扮演的角色。
作为概念的角色与关联中的角色
在领域模型中,可以采用多种方式建模现实世界的角色。
第一种方案可称为“关联中的角色”,这种方案更具吸引力,因为它相对准确地反映了“同一个人在各种关联中可以扮演不同的角色”这一关联。我,作为一个人,可以同时或者按顺序扮演作者、对象设计者、父亲等角色。
第二种方案称为“作为概念的角色”,这种方案在添加熟悉感、挂链和附加语义方面具有更大的灵活性。进一步而言,当角色改变时,当前流行的面向对象编程语言都不能很方便地动态地将某个类的实例转换成另一个类的实例,因此将角色实现为单独的类比较容易。
导出元素
导出元素可以由其他元素所确定。属性和关联时最常见的导出元素。
要避免在图中现实导出元素,因为这些导出元素在没有增加新信息的情况下还会增加复杂性。然而,如果导出元素时重要的术语,而缺乏这一术语会消弱理解,这是就需要在图中增加导出元素。
受限元素
在关联中可能会永奥限定词;基于限定词的值可以区分位于关联另一端的对象集合。具有限定词的关联时受限关联。
自反关联
概念到自身的关联称为自反关联。
使用包来组织领域模型
领域模型可以很轻易地发展到足够大,这时理想的做法是把它分解成与概念相关的包,因为这样有助于理解,并且有利于由不同的人在不同的子领域并行的进行领域分析工作。
如何划分领域模型
将领域模型划分为包结构时,将满足下述条件的元素放在一起:
- 在同一个主题领域,概念或目标密切相关的元素。
- 在同一个类层次结构中的关系。
- 参与同一个用例的元素。
- 由很强的关联性的元素。