类的理解与总结

最近在学习如何用UML对系统进行建模,其实两三年前就试着去学习去做,无奈当时的经验比较少,理解能力有限。经过这几年的开发实践,现在是时候重新学习了。 使用UML对系统进行建模是每个软件开发者都应该学习与掌握的必备技能。前几篇博客,有几篇是关于如何用PlantUML绘制UML图的,也很有意思。不过,我将暂时中止PlantUMl的学习。 毕竟它只是一个UML的工具,工具有很多种,但理是不变的。所以,近一两个月将集中学习下UML的理论知识,Grady Booch的《UML用户指南》是本不错的书。 接下来的几篇博客将是我学习过程自己的一些思考,总结与笔记。一来备忘而来与各位分享。本文是对第四章类的一些思考与总结。

1 软件系统建模的隐喻

架构(Architecture)这个在软件系统中经常使用的词汇最早源于建筑工程。通过对建筑工程建模的描述可以帮助我们理解软件系统建模。

假如正在假造一所房子,那么像墙、门、窗户、橱柜和灯对于房主来说是重要的事务。这些事务中的每一个都有别于其他事务,有自己的一组特性。墙有高度和宽度,是立体的。 门有高度和宽度,也是立体的,但它还有额外的行为,能朝一个方向打开。窗户和们类似,二者都是在墙上开的洞,但它们稍有不同。窗户通常(但不总是)设计得让人能向外看, 而不是让人穿行。

墙、门和窗户很少作为个体单独存在,因此还必须要考虑怎样把这些事务的具体事例组合在一起。识别事务和选择他们之间所要建立的关系将受下述因素影响:希望如何使用住宅的各个房间, 希望各个房间如何联通,以及希望这种布局所形成的总体风格和感觉。

用户所关心的失误各不相同。李儒,帮助建房的水管工对排水管、存水弯和通风口之类的事务感兴趣。作为房主,就不需要关心这些事务,只需关心水管工对这些东西的施工要满足要求, 例如,排水管要安装在地下,通风口要穿过屋顶。

说白了,建模就是一种抽象, 它跟观察者的角度有关 。这也就是为什么UML有4+1视图模型的原因。因为软件开发过程涉及到很多的角色,每个角色的专注点不同,抽象也就不同。 例如,需求分析人员对用例图比较感兴趣而开发人员对逻辑视图、过程视图比较感兴趣。

An abstraction denotes the essential characteristics of an object that distinguish it from all other kinds of objects and thus provide crisply defined conceptual boundaries, relative to the perspective of the viewer.

2 类的术语和概念

软件开发是一个从逻辑抽象到物理实现的过程。在面向对象系统中,类是抽象过程中非常重要的一个概念,也是一个最重要的构造块。

类是对一组具有相同属性、操作、关系和语义的对象的描述。一个类可以实现一个或多个接口。结构良好的类具有清晰的边界,并形成了整个系统的职责均衡分布的一部分。

从某种意义上来说,类是描述对象的元数据(Meta Data),我是这样认为的。

2.1 名称

每个类都必须有一个有别于其他类的名称。名称(name)是一个文字串。单独的名称叫做简单名,有类所在的包的名称作为浅醉的类名叫做限定名。

实践中,类名称一般由首字母大小的简单名词或者名词短语组成。

2.2 属性

属性(attribute)是已命名的类的特性,它描述了该特性的实例可以取值的范围。类可以有任意数目的属性,也可以没有属性。属性描述了正被建模的失误的一些特性, 这些特性为类的所有对象所共有。例如每一面墙都有高度、宽度和厚度。

命名规则与名称类似,都是由简单名词或者名词短语来命名。

2.3 操作

操作(operation)是一个服务的实现,该服务可以由任何类的对象来请求以影响其行为。换句话说,操作是能对一个对象所做的事情的抽象,并且它由这个类的所有对象共享。 类可以有任意数据的操作,也可以没有操作。

当给一个对象发送消息时,该消息必须是类可以理解的,这才是好的系统隐喻,也是才是合理的。

2.4 对属性和操作的组织

在画一个类是,不必同时把所有的属性和操作都显示出来。事实上,在大多数情况下不能这样做(由于属性和操作太多以至于无法把他们放在一张图中),也可能不应该这样做( 可能只有这些属性和操作的一个子集与特定的视图相关 )。 所以,空栏并不一定意味着没有属性或操作,只是没有选择要显示他们。

为了更好地组织属性和操作的长列表,可以利用构造型(Stereotype)在每一组属性和操作之前加一个描述其种类的前缀。

原文翻译成 衍型 ,不过我还是觉得 构造型 顺口, 因此以后都称之为构造型。另外,由于抽象跟观察者的角度有关,因此有选择地显示观察者所关注的属性和操作。

2.5 职责

对类建模的一个号的起点是详述词汇表中的事务的职责。像CRC卡和基于用例的分析技术在这里特别有用。当精化模型时,要把这些职责转换成能很好地完成这些职责的一组属性和操作。 在图形上,把职责列在图形符底部的单独的栏中。也就是说与属性和操作一样,单独占一栏。

2.6 其他特征

例如属性和操作的可见性;与特定语言相关的操作特征,例如多态的或者静态的。另外类也有内部结构的,可以类的内部结构图描述属性之间的关系。

3 常用的建模技术

3.1 对系统的词汇建模

为了对系统的词汇建模,需做如下工作:

  • 识别用户或实现者用于描述问题或者描述解决方案的那些 事务 。用CRC卡和基于用例分析的技术帮助用户发现这些抽象。
  • 对于每个抽象,识别一个 职责集 。确保能清楚地定义每个类,而且这些职责能在所有的类之间很好地均衡。
  • 提供为实现每个类的职责所需要的 属性和操作

其实这些都是环环相扣的: 识别 事务 -> 找出 职责集 -> 将职责转化为 属性和操作

随着模型的不断增大,所发现的很多类将趋于蔟集到一些概念和语义上相关的组中。在UML中,可以用包来对这些类簇建模。

其实一切都是那么自然,类过多时会变得杂乱不堪,可以用包进行组织。分解,抽象,分类是解决复杂问题的基本手段。

3.2 对系统的职责分布建模

对系统中的职责分布建模,要做如下工作:

  • 识别一组为了完成某些行为而紧密地协同工作的类。
  • 对上述的每一个类识别出一组职责。
  • 从整体上惯着这组类,把职责过多的类分解成较小的抽象,把职责过于琐碎的小类合并成较大的类,重新分配职责以使每一个抽象合理地存在。
  • 考虑这些类的相互协作方式,相应地重新分配他们的职责,使协作中没有哪个类的职责过多或者过少。

我认为:

  1. 这里也需要考虑系统隐喻
  2. 平衡类的职责在一定程度上跟代码的可测试性有关系,为了使类更具有可测试性,我们通常需要调整职责分布,使对象的邻居对象不至于过多或者过少。 邻居对象过多意味着该对象的职责太少,反之意味着该对象的职责太多,这两种情况都会降低类的可测试性。 说白了,平衡类的职责的手段有三种:
    • 创建一个不存在的类
    • 将一个大类拆分成多个小类
    • 将多个小类合并成一个较大的类

3.3 对非软件事物建模

为了对非软件事物建模,要做如下工作:

  • 对抽象为类的事物进行建模。
  • 如果要将这些非软件事物与UML已定义的构造快相区别,就要创建一个新的构造快,用构造型详述这些新语义,并给出不同的可视化提示。
  • 如果建模的事物是某种本身包含软件的硬件,考虑把它建模为一种结点,以便能进一步扩充它的结构

系统外部的事物经常被建模为参与者。

3.4 对简单类型进行建模

对简单类型建模,要做如下工作:

  • 对抽象为类型或者枚举的事物进行建模,这可以用带有适当构造型的类表示符来表示。
  • 若需要详述与该类型相联系的值域,可以使用约束。

4 总结

这些基本上就是第四章的内容,有些图片没来得及加上去,以后有机会再加上去吧。