《设计模式解析》第2章 UML——统一建模语言

类别:软件工程 点击:0 评论:0 推荐:
第2章 UML——统一建模语言 概述

       本章对统一建模语言(UML)给出了一个简短的概述,它是面向对象社团的建模语言。如果你不曾了解UML,本章将会让你对它有一个最小的理解,以便你能够读懂本书所包含的图形。

       在本章,

l           我将描述什么是UML以及为什么要使用它。

l           我将讨论对本书很重要的UML图:

       ——类图

       ——交互图

什么是UML

       UML是一种用于创建程序模型的可视化语言(意味着一种带语义的图形标记)。对于程序模型,我指的是程序的一种图形化表达,我们能从中看到存在于代码之中的对象之间的关系。

       UML有好几种不同的图——有的用于分析,有的用于设计,还有的用于实现(或者更准确地说,用于散播,即代码的发布)(参见表2-1)。根据不同的目的,每一种图展示了不同实体集之间的关系。

表2-1 UML图及其目的

当你……

使用UML图……

在分析阶段

用例图,它们包含和系统交互的实体(比如说,用户和其它系统)以及我需要实现的功能点。

活动图,它们将焦点集中于问题域(人们以及其它主体工作的实际空间,程序的主题域)的工作流而不是程序的逻辑流。

注意:因为本书主要基于设计,我将不会在此涉及到用例图或者活动图。

观察对象交互

交互图,它们展示特定的对象彼如何此交互。由于它们处理特定案例而不是一般情况,因此它们在检验需求和检验设计时都能有所帮助。最流行的交互图是顺序图。

在设计阶段

类图,它们详述类与类之间的关系。

观察对象的行为,这些行为因对象所处的状态而不同

状态图,它们详述一个对象可能处于的不同状态以及这些状态之间的过渡。

在布署阶段

布署图,它们展示了不同的模块将被如何部署。我不会在此讨论它们。

 

为什么使用UML

       UML主要用于交流——和我自己,我的团队成员,以及我的客户。在软件开发领域,糟糕的需求(或者不完整或者不准确)普遍存在。UML给我们工具去收集更好的需求。

       UML给我们方法去判断自己对系统的理解是否和别人一样。由于系统是复杂的,有着不同种类的必须表达的信息,UML提供不同的图以专门表达不同的信息。

       一个看到UML价值的简单方法是回忆你上一次的几个设计评审。如果你曾经身处评审,在那里人们开始讨论并描述他们的代码,但却没有一种类似UML的建模语言,可以肯定,他们的谈话不仅令人费解而且非常费时。UML不但是描述面向对象设计的一个好方法,而且还迫使设计人员在他或她的整个过程中(因为它必须被写下来)去思考。

类图

       UML图中最为基础的是类图。它描述类以及类与类之间的关系。关系的类型可能有:

l           当一个类是另一个类的一“种”:is-a关系

l           当两个类之间存在关联

       ——一个类“包含”另一个类:has-a关系

       ——一个类“使用”另一个类

这些主题各有变数。比如,说某物包含其他某物这可能意味着

l           被包含者是包含者的一部分(就像汽车中的引擎)。

l           我有一组能够独立存在的事物(就像飞机场上的飞机)。

第一个例子被称为组合,而第二个例子则被称为聚合[1]。

图2-1描述了几件重要的事情。首先,每一个矩形代表一个类。使用UML我可以表示类的三种东西:

l           类的名字

l           类的数据成员

l           类的方法(函数)

图2-1 类图——它的三个变种。

我有三种不同方法去展示这些东西。

l           最左边的矩形只显示了类的名字。在不需要更多详细的信息时,我就会使用这种方式来表达类。

l           中间的矩形显示了类的名字和方法。其中,Square[2]类有display方法。display(方法的名字)前的加号(+)表明这个方法是公有的——这就是说,其它类的对象也能够调用它。

l           最右边的rectangle显示了我之前有的东西(类的名字和方法)以及类的数据成员。其中,数据成员length(类型为double)前面的减号(-)显示了这个数据成员的值是私有的,也就是说除了它所属于的那个对象,没有任何其它东西可以访问它[3]。

UML用于访问的标记法

你可以控制类的成员数据和方法的可见性。你可以使用UML为每一个成员标记你所希望的可见性。以下是在大多数面向对象语言中存在的三种可见性:

l           Public:用加号(+)标记。

这表明所有对象都可以访问这个数据或方法。

l           Protected:用井号(#)标记。

这表明只有这个类以及所有它的派生类(包括它的派生类的派生类)能够访问这个数据或方法。

l           Private:用减号(-)标记。

这意味着只有这个类的方法可以访问这个数据或方法。(注意:某些语言进一步将限制局限在特定的对象之上。)

类图也可以展示不同类之间的关系。图2-2显示了Shape类和它的几个派生类之间的关系。

图2-2 展示is-a关系的类图

       图2-2展示了几件事情。首先,Shape类下面的箭头意味着指向Shape的几个类都是从Shape派生。还有,Shape的斜体意味着它是一个抽象类,用于为它的派生类定义一个接口。

       事实上有两种不同的has-a关系。一个对象可以拥有另一个对象,其中被包含的对象是包含对象的一部分——或者不是。在图2-3中,我展示了飞机场“拥有”飞机。飞机不是飞机场的一部分,但是我依然可以说飞机场拥有它们。这类关系被称作聚合。

图2-3展示has-a关系的类图

       在这个类图中,我也展示了一架飞机要么是一架喷气机要么是一个直升机。可以看出Aircraft是一个抽象类,因为它的名字是斜体。这表明一个飞机场将会拥有喷气机或者直升机,但会将他们视为相同的东西(飞机)。Airport类右边的开放(空心)菱形展示了聚合关系。

       另外一种has-a关系中的包含说明被包含的对象是包含对象的一部分。这类关系也被称作组合。

图2-4 展示组合及使用关系的类图

       图2-4表明轮子是一辆汽车的一部分(那就是说,汽车由轮子和其它东西组成)。这种被称作组合的has-a关系用实心菱形来表示。这张图也表明一辆汽车使用一个加油站。这种使用关系用一条有箭头的虚线来表示,也被称作依赖关系。

       无论是组合还是聚合,它们都包含一个对象包含一个或多个其他对象的情况。然而,组合暗示着被包含的对象是包含对象的一部分,而聚合则意味着被包含对象更像是一组事物。我们可以认为组合是一种不被共享的关系,其中,被包含对象的生命期由它的包含对象控制。在这里,适当地使用构造方法和析构方法会使对象的创建和销毁变得更加容易。

图2-5 使用注释的类图

UML中的注释。

       图2-5中出现一个新的符号:注释。其中,那个包含 “开放菱形意味着聚合”消息的方框就是一个注释。他们看起来就像右角向后折起的纸片。你会经常看到一条直线将它们连接到一个特定的类,这表明它们和那个类相关联。

       类图展示了类与类之间的关系。而使用组合和聚合,在那种类型类的对象方面,这种关系会更加明确。比如,飞机场确实拥有飞机,但更明确的说,特定的飞机场会拥有特定的飞机。现在问题就来了——“一个飞机场会拥有多少飞机呢?”这叫做关系的基数。我在图2-6和2-7中展示了这一点。

图2-6 飞机场-飞机关系的基数

       图2-6告诉我们,当我有一个飞机场时,它有0到任意数量(此处用一个星号表示,但有时用字母“n”表示)的飞机。Airport边上的“0..1”表明当我有一架飞机时,它可以被0个或1个飞机场所包含(它可能在空中)。

图2-7 汽车-轮胎关系的基数

       图2-7告诉我们,当我拥有一辆车时,它有4个或5个轮胎(它可能有或没有一个备用轮胎)。而轮胎则准确地在一辆车上。我听说在没有指定基数时,有些人假定这表明有一个对象。这是不对的。如果没有指定基数,这表明没有作出存在多少对象的假定。

       和以前一样,图2-7中Car和GasStation之间的虚线表明它们之间存在着依赖。UML使用一条带箭头的虚线表示两个模型元素之间的语法关系(含义)。

交互图

       类图显示了类之间的静态关系。换句话说,它们不向我们展示任何行为。这虽然很有用,但有时候我需要展示从这些类实例化的对象实际上是如何一起运作的。

       显示对象是如何彼此交互的UML图叫做交互图。最常见的交互图是顺序图,正如图2-8所示。

       我们从顶至底来阅读顺序图。

l           顶部的每一个矩形代表一个特定的对象。虽然很多矩形中有类名,注意类名前面的冒号。有些矩形还有其它的名字——比如shap1:Square。

l           顶部的盒子给出了类的名字(冒号的右边)以及一个可选的对象名字(冒号的前面)。

l           垂直线表明了对象的寿命。不幸的是,大多数UML绘图程序不支持这一点,它们将直线从顶画到底,这使得一个对象实际上从什么时候产生变得很不明朗。

l           我展示了对象通过这些垂直线之间的水平线向彼此发送消息。

l           有时候返回值和/或对象被明确显示,而有时候这表达得很含蓄。

图2-8 形状程序的顺序图

       比如,在图2-8中,

l           在顶部,我看到Main发送一条“获取形状”的消息给一个ShapeDB对象(没被命名)。在被请求“获取形状”之后,ShapeDB会:

       ——实例化一个集合

       ——实例化一个正方形

       ——将正方形加入到集合之中

       ——实例化一个圆

       ——将圆加入到集合之中v

       ——将集合返回给调用程序(Main)

我通过这种从顶至底的方式阅读该图的剩余部分,理解剩余的动作。这种图之所以被称作顺序图,是因为它显示了动作的次序。

对象:类标记

       在一些UML图中,你想要引用一个对象,并表明它从哪一个类所派生。这点可以通过用一个冒号连接它们而达到。在图2-8中,shape1:Square指的是从Square类实例化的shape1对象。

总结

       UML的目的是充实你的设计并交流它们。不要过于担心是否在以“正确”的方式创建图形,你只需考虑以最好的方式去交流设计中的概念。换句话说,

l           如果你觉得有些事需要说,那就使用一个注释去表达它。

l           如果你不太确定一个图标或者一个符号,并且不得不通过查找以得到它的含义,那就是用一个注释去解释。因为别人也可能不清楚它的含义。

l           去作澄清。

       当然,这意味着你不应该以不标准的方式来使用UML——那样同样无法正确交流。画图时,仅仅考虑你想要交流什么就行了。

[1] Gamma,Helm,Johnson,和Vlissides(四人团)称第一种为“聚合”,第二种为“组合”——恰好和UML相反。然而,四人团的书写在UML最终确定之前。而事实上,他们现在的定义和UML的是一致的。这说明了对UML的一些动力。在UML出现前有好几种不同的建模语言,每一种都有它自己的标记法和术语。

[2] 和这里一样,在任何地方我们用粗体来引用一个类名。

[3] 在某些语言里面,同种类型的对象能够共享它们的私有数据。

本文地址:http://com.8s8s.com/it/it34957.htm