Thinking in UML 学习笔记 | 第二章 建模基础
第二章建模基础
2.1建模
建模(Modeling),是指通过对客观事物建立一种抽象的方法用以表征事物并获得对事物本身的理解,同时把这种理解概念化,将这些逻辑概念组织起来,构成一种对所观察的对象的内部结构和工作原理的便于理解的表达。
为了理解,我们简单地说:“建模包含了两个问题,一个是怎么建?另一个是模是什么?”
第一个问题“怎么建”,依赖于方法论,再上升一点到哲学高度就是认识论。
UML建模必须采用面向对象的观点。
我们在看待事物的时候,在不知不觉中,每一组相同点和不同点都来自于你的一个抽象角度。
抽象角度的不同决定了建模方向的不同。当你试图为现实世界建模的时候,首先要决定的是抽象角度,即建立这个模型的目的是什么。一旦抽象角度确定,剩下的事情就变得顺理成章,而不再是杂乱无章。
具体来说,做需求的时候,首要目标不是要弄清楚业务是如何一步一步完成的,而是要弄清楚的有多少业务的参与者?每个参与者的目标是什么?参与者的目标就是你的抽象角度。
第二个问题“模是什么?”,则依赖于确定了抽象角度下的场景模拟。
前面说过,确定了抽象角度就是确定了一个目标。现在要做的事情便是找出那些能够满足这一目标的事物。有趣的是,我们找出这些事物的过程并不是面向对象的,而是过程化的。我们必须要搞清楚谁发出了什么动作,作用于什么事物,产生了怎样的后果。显然这是过程化的。但是我们的这个过程是为了找出场景中贡献于场景目标的那些事物,以及这些事物是如何贡献于这个场景的。也就是说场景模拟帮助我们找出抽象的对象,而场景本身则是这些对象在一定条件下交互的一个特定的结果。
回到什么是模的问题来,一个由抽象角度确定了的目标需要由静态的事物加上特定条件下产生的一个特定的场景来完成,即静态的事物(物)+特定的条件(规则)+特定的动作(参与者的驱动)=特定的场景(事件,即完成目标的过程)。
“模”就是“人”、“事”、“物”、“规则”。
人=业务主角(BusinessActor)、业务工人(BusinessWorker)、参与者(Actor)等;事=业务用例(BusinessUseCase)、系统用例(UseCase)等;物=业务实体(BusinessEntiry)、实体(Entity)等。
业务建模到底是什么?如果你还没有理清楚,下面的这些公式应该会帮助你理清思路。
问题领域=n个抽象角度累加抽象角度=问题领域边界之外的参与者的业务目标=业务用例业务用例=n个特定场景累加特定场景=静态的事物+特定的条件+特定的动作或者特定的事=特定的事物+特定的规则+特定的人的行为请牢记这些公式,不仅仅是业务建模,分析建模、设计建模都遵从同样的公式,无非是i公式中的变量更换了马甲。
2.2用例驱动
让我们再次回顾建模公式,很容易得出一个推论,要解决问题领域就要归纳出所有必要的抽象角度(用例,目标),为这些用例描述出可能的特定场景(完成目标的过程),并找到实现这些场景的事物、规则和行为。换个说法,如果我们找到的那些事物、规则、行为实现了所有必要的用例,那么问题领域就被解决了。总之,实现用例是必须做的工作,一旦用例实现了,问题领域就解决了。这就是用例驱动方法的原理。
在实际的软件项目中,一个软件要实现的功能通过用例来捕捉,接下来的所有分析、设计、实现、测试都由用例来驱动,即以实现用例为目标。
用例可以驱动的内容包括:
逻辑视图。系统只有一个逻辑视图,该视图以图形方式说明关键的用例实现、子系统、包和类,它们包含在架构方面具有重要意义的行为,即建模公式中的那些“人”、“事”、“物”、“规则”是如何分类组织的。进程视图。系统只有一个进程视图,该视图以图形方式说明了系统中进程的详细组织结构,其中包括类和子系统到进程和线程的映射,即建模公式中的那些“人”、“事”、“物”、“规则”是如何交互的,它们的关系如何。这个视图是我们常说的分析设计视图。部署视图。它以图形方式说明了处理活动在系统中各节点的分布,包括进程和线程的物理分布,即建模公式中的那些“人”、“事”、“物”、“规则”是如何部署在物理节点(主机、网络环境)上的。实施视图。该视图的作用是获取为实施制定的架构决策。该视图通常包括以下内容:列举实施模型中的所有子系统。描述子系统如何组织为层次和分层结构的构件图。
描述子系统间的导入依赖关系的图解。
实施视图用于:
为个人、团队或分包商分配实施工作。
估算要开发、修改或删除的代码数量。
阐明大规模复用的理由。
考虑发布策略。
也就是:建模公式中的那些“人”、“事”、“物”、“规则”如何构成系统的“零部件”,以及我们如何组织人力生产和组装这些“零部件”以建成最终系统。
2.3抽象层次
首先,在面向对象方法里,需要提高抽象层次,用一个新的概念来概括一部分相关的信息,一旦人们消化了这个新的概念,理解起来就变得容易了。同时,这个新的概念就屏蔽了(或者说封装了)更多具体的信息。抽象层次越高,被屏蔽的信息就越多,信息量就越少,也就越容易理解和处理。
但是,抽象层次太高,信息量过少会导致信息量不足,这时候人们在实施起来就会有困难。因此,在适当的时候采用适当的抽象层次是十分重要的。它直接反映到如何选择用例的粒度上。
在软件开发中,主题上应当采用自顶向下的方法,用少量的概念覆盖系统需求,再逐步降低抽象层次,知道代码编写。同时辅以自底向上的方法,通过总结在较低抽象层次的实践经验来改进上层概念,以提升软件质量。这是一个反馈、迭代的过程。
与抽象层次相关的另一个问题是边界,它们的选择总是相生相伴的。
2.4视图
人们在认识现实世界中的事物的时候,只有在了解了很多关于这个事物的很多个方面(属性)后才能够对这个事物真正理解。但是很多时候,仅给出所有属性的视图是不够的,因为这时候给出的信息不是很清晰,而人们更多的是希望从更多的角度来查看事物的信息,这就引出了另外一个非常重要的概念:视角。
视角是人们观察事物的角度。“横看成岭侧成峰”诗句就能很好的表达。
恰当的视角可以让观察者更容易抓住信息的本质;观察者只会关心信息中他感兴趣的那一部分视角。
回到建模工作来,建立模型的目的是向相关的人展示将要生产的软件产品,一个软件产品有着很多个不同的方面。只有把这些方面都描述清楚,用很多个不同的视图去展示软件这些不同的方面——静态的、动态的、结构性的、逻辑性的等——才能够说建立了一个完整的模型。为了说明这些不同的方面,UML里定义了用例图、对象图、类图、包图、活动图等不同的视图。所以,建模最主要的工作就是为软件绘制那些表达软件含义的视图来完整地表达软件的含义。
同时,由于软件的干系人很多,有客户、系统分析员、架构师、设计师、开发人员、测试人员、项目经理等,他们对同样信息的审视角度是不同的。因此建模另一项重要的工作就是为不同的干系人展示他们所关心的那部分视角。
在实际工作中要经常思考这两个问题:
1、应该为哪些软件信息绘制哪些视图?
2、应该给哪些干系人展示哪些视角?
2.5对象分析方法
一切都是对象对象都是独立的。对象与对象之间是天然独立的,只是在某个特定的场景下,它们的某一个特定的实例才相互联系在一起。场景中的对象只是对象“映射”到该场景中的一个侧面,我们称之为对象实例。换言之,通过一个场景,我们仅能得到对象的一个侧面的信息。所以要深入了解对象,我们经常需要分析很多个该对象的实例所参与的场景,以获得对象的多个侧面,再通过归纳整理这些对象的多个实例抽象出对象的一般特性。这就是对象的分析方法,同时也是使用UML来为对象建模时所采用的方法。从每个场景看到的仅是对象映射到该场景的一个方面,或者说是一个实例,它仅仅是对象分析的开始。请记住,当采用面向对象的方法时,在需求、分析、设计过程中,你所得到的任何一个有名字的东西,不论是用例、类、包、组件等都是独立于那个场景的,不要将对象局限在那个场景中。对象的独立性带来的正是对象的可抽象能力和可扩展能力。
对象都具有原子性。无论什么时候,在分析过程中,都应当将对象当做一个不可分割的原子,哪怕这个对象的规模很大,不论它有多么的巨大,只要我们认为它是对象,它与其他对象交互时就是一个整体,不能分割。在分析过程中,对象总有一个边界。我们应当将分析过程中得到的所有关于对象的认识附加在对象边界上,在实现这个对象之前不理会其内部的细节。这称之为面向接口编程。对象都是可抽象的。对象所具有的方面,或者说对象所参与的场景越多,对象越有抽象价值,反之则越没有抽象价值。因此在分析过程应当关注那些参与了很多场景的对象,它们往往是分析设计中的重点以及成败关键。对方面的抽象通常用接口命名。对象都有层次性。对象分析方法总结:独立性、原子性、抽象性和层次性是面向对象分析时应当遵循的一些原则和方法。在实际工作中,需要考虑以下几个方面。一个场景对应一个对象实例,通过对象分析得到对该方面的一个抽象,通过对多个这样的方面的分析,慢慢完善对象本身。而对于不同场景,对象描述的抽象层次是不同的。