想像一下,如果您的团队中的每个人都在说不同种类的语言。假设你说德语,你的同事说法语,别的同事在说希伯来语。每次有人发言,其他人都“收获了什么东西”,然后点点头,貌似他们已经完全理解了。其实他们走进了一个完全错误的解释,这不是发言者真正想表达的话。在几乎所有IT项目中,沟通不畅的问题都很“猖獗”,但是人们却很少注意到,因为每个人都认为他们使用相同的“语言”,其实根本不是。比如:一个人说“书评”(book review”),有些人将其解释为“编辑评论”(”editorial review“由编辑小组撰写的评论),而其他人可能将其解释为“客户评论”(“customer review”由客户撰写的评论,并发布到现场)。结果经常是灾难性的,因为系统在开发的过程中,每个人都会以不同的方式解释需求和设计。
领域模型是一个灵活的,协作的”工做组件“。它对整个项目进行了细化和更新,从而反映了目前对“问题空间(或需求空间)”的理解。在本文中,我们将介绍领域建模,其目的是通过建立映射问题空间的常用词汇来解决项目沟通不畅的问题。
万尺视图:
域建模是构建项目词汇表或项目中使用的词典的任务。项目的领域模型定义了范围,并形成了构建用例的基础。域模型还提供了一个常见的词汇表,以便能够在项目团队成员之间进行明确的沟通。所以即使这本书是关于用例驱动的开发,我们必须从一开始就开始使用域建模。
什么是领域模型?如前所述,域模型本质上是项目词汇表:项目中使用的所有术语的“实时”字典。但领域模型比项目词汇表更好,因为它以图形方式显示了所有这些不同的术语如何相互关联。实际上,它是一个简化的类图,在不同的类(领域对象)之间使用线条进行描绘,以显示它们如何相互关联。领域模型显示领域类之间的聚合和泛化关系(has-a和is-a关系),下图是一个领域模型的例子。
为什么开始使用域模型而不是用例?
你会发现,如果您在项目开始时快速构建出了领域模型,那么它真的有帮助。当你从项目一开始就使用用例的时候,很容易使它们变得抽象,高级(high-level),模糊(vague)和双关(ambiguous.)。事实上,有些“大牛”甚至建议你用这种方式写你的用例(只有他们称之为“抽象的”,“必要的”,“无技术的”等等)。我们的建议恰恰相反:您的用例文本应基于现实,它应该非常接近您将要设计的系统。换句话说,用例应该写在对象模型的上下文中(即用例文本需要通过名称引用域对象)。通过这样做,您将能够将模型的静态和动态部分结合在一起,如果您希望根据用例推动您的分析和设计工作,这是至关重要的。因此,在编写用例之前,您需要先对领域模型进行一次尝试。领域模型构成了您的模型的静态部分的基础,而用例是动态部分的基础。静态部分描述结构;动态部分描述行为。
(分析层面上,术语“对象”和“类”有时可互换使用(一个对象是类的运行时实例)。然而,当我们得到更接近的设计水平时,这个区别对象和类之间变得更加重要。)
十大领域建模指南:
10.关注现实世界(问题领域)对象。
9.使用泛化(is-a)和聚合(has-a)关系来显示对象如何相互关联。
8.将您的初始域建模工作限制在几个小时。
7.围绕问题领域的“关键抽象”来组织您的类。
6.不要将您的领域模型误认为数据模型。
5.不要将一个对象(代表单个实例)与数据库表(其中包含事物的集合)混淆。
4.使用领域模型作为项目词汇表。
3.在您编写用例之前,先做一些初始域模型,以避免使用名称歧义。
2.不要指望您的最终类图精确匹配您的领域模型,但他们之间应该有一些相似之处。
1.不要在您的域模型上放置屏幕(screens)和其他GUI特定的类。
10. Focus on Real-World Objects
创建领域模型时,请确保将问题领域与实际对象集中在一起。 尝试着围绕现实世界来组织您的软件架构。 现实世界往往比软件需求变化要小。下图显示了两种不同类型的类符号。在完整的详细类图上,您将使用左侧的版本,其属性和操作。然而,在初始领域建模过程中,分配类的这些部分为时尚早。最好使用右边所示的简单符号。此版本仅显示领域类的名称。
9. Use Generalization (Is-a) and Aggregation (Has-a) Relationships
随着时间的推移,您将会使用新的领域类别来识别您的领域模型。您还会注意到他们之间的联系(或关联) - 例如,书评属于书,采购订单(purchase order)和信用卡(credit card)是两种,因为它们都是付款类型。
第一个关系(书评属于一本书)被称为聚合(has-a,因为一本书都会有一书评)。第二个关系(采购订单和信用卡都是付款类型)被称为泛化(is-a,因为采购订单是付款类型)。图2-3显示了这些概念的说明。
这些所谓的一般关系是您的领域模型中最重要的关系。您可以使用聚合和泛化关系建模您的模型的类关系中的百分之九十五。尽可能不要使用“关联”,使领域模型从左到右和从上到下阅读,就像普通文本一样。 这将提高您的图表的可读性(这句话可以不用在乎)。
8. Limit Your Initial Domain Modeling Efforts to a Couple of Hours
我们建议您做一个时间预算来构建您的初始领域模型,可能需要几个小时,你不会使它完美无缺,所以做得很快,并希望在项目进行中不断修复它。您应该保持警惕,对您的分析级别类模型进行必要的调整,以响应在鲁棒性分析和整个项目期间发现的发现(You should be vigilant about making necessary adjustments to your analysis-level class model in response to discoveries made during robustness analysis and throughout the project)。
当您使用用例和鲁棒性图表时,您会发现缺少的对象。用例驱动的过程会假定领域模型不完整,并提供了发现遗漏的机制。
一开始您做的领域建模可能是您在项目上花费的最重要的两个小时! 在这两小时的头脑爆发期间,您可能会发现80%的域名类。如果您可以将80%的领域名词汇消除歧义,那么花费两个小时。
7. Organize Your Classes Around Key Abstractions in the
Problem Domain
围绕在领域问题中的的”关键抽象“ 组织您的类通常是一个很好的做法。请记住,领域模型是一个先进的类图,成为您的软件架构的基础。这使得模型面对变化更有弹性。围绕现实世界的抽象组织架构使得模型在面对不断变化的需求方面更有弹性,因为需求通常会比现实世界更频繁地变化。
6. Don’t Mistake Your Domain Model for a Data Model(选看)
即使这些图可能相似,但请记住,数据模型的良好做法在类图上可能不是良好的做法(反之亦然)。 类很小,表比较大。关系数据库中的表通常涉及许多事情。相反,如果它是一个相对较小的数据和行为(方法)包,则用类去设计会更好。
在类图中,您可能会有一个管理数据库表的类,您可能会显示一些聚合常规域类的TableManager类。这TableManager类型类的目的是从代码库的其余部分隐藏数据库管理系统(DBMS)的详细信息。
(In a class diagram, it’s likely that you’ll have a class that manages a database table, and you might show some sort of TableManager class aggregating a regular domain class. The purpose of these TableManager-type classes is to hide the details of the database management system (DBMS) from the rest of the code base.)
5. Don’t Confuse an Object with a Database Table
一个对象代表一个单一的东西。数据库表表示事物的集合。您不必像企业JavaBeans(EJB)世界中的文字一样,实体bean通常表示表中的单个行。领域类是相似的。如果你调用一个领域类图书,那么并不意味着书表(数据库里面没),而是是一本书。数据库表中的列通常映射到类上的属性。
但是,数据库表通常包含比包含属性更多的列(表通常具有外键作为一个示例),因此表行和对象之间可能没有直接的1:1映射。
4. Use the Domain Model As a Project Glossary
如果模糊的要求(二义性)成为了你的敌人,那么领域模式就是第一道防线。“项目领域主题专家”对名称的二义性命名和使用是非常普遍但却是非常有害的(对同一个词汇有不同的叫法)。领域模型应作为项目词汇表,有助于在描述问题空间时确保术语的一致使用。使用领域模型作为项目词汇表是消除模型歧义的第一步。在Doug教授的每一个Jumpstart教学中,他发现至少有两到三个领域名类,其中学生使用不明确的名称(例如“购物车shopping cart,””,“购物篮shopping basket”或“购物车shopping trolley”)。
3. Do Your Domain Model Before You Write Your Use Cases
由于您使用域模型来消除问题领域的抽象,因此使用不明确的术语编写用例来描述域类是很愚蠢的。因此,在编写用例之前,请花两个小时在领域模型上工作。编写没有域模型的用例将所有内容绑定在一起存储很多问题以供以后使用
2. Don’t Expect Your Final Class Diagrams to Precisely Match Your Domain Model
随着设计的进行,类图将比域模型更加详细;域名模式故意保持相当简单。在设计(使用序列图)时,详细的设计构造(如GUI帮助器,工厂类和基础架构类)将添加到类图中,领域模型图几乎可以分解成几个详细的类图。然而,仍然可以将大多数类追溯到等效的领域类。
1. Don’t Put Screens and Other GUI-Specific Classes on Your Domain Model
这样做会打开潘多拉的盒子,并导致一个拥挤的领域模型,其中包含许多实现特定的细节。性能优化类,助手类等也应该保留在域模型之外。领域模型应该只关注问题领域。
Extracting the First-Pass Domain Model from High-Level Requirements
当您创建领域模型的时候,一个良好的领域类包括很多高级要求-通常(但不总是)是以”系统应该这样做“的形式编写要求,或者是”系统不应该这样做“。扫描这些要求,提取名词和名词短语,然后,您可以定义这些名词或者短语来创建出事领域模型。