目的
画UML图有好多种工具,VISIO只是其中一种.VISIO的动作非常轻快.很多人都在用.但是对众多的C++程序员来讲,存在着一个问题,那就是VISIO中的用语都来自面向对向,和C++程序员常用的说法有所不同.这一点令很多C++程序远很困惑.希望本文能为您解决这个问题. 在我们将使用下面的例子(UMLSample.zip)来进行说明。
启动Visio
然后选择[File]-[New]-[Software]-[UML Model Diagram]就可以进入到UML作图状态了.这时画面至少应该包含3个部分:形状窗口,模型资源管理器,和作图区域.可以通过选择[View]-[Shapes Window]来表示和隐藏形状窗口.模型资源管理器比较麻烦,必须通过[UML]-[View]-[Model Explorer]来进行.
创建各种图面
在模型资源管理器中选择[Static Mdel]-[Top Package],点鼠标右键,从弹出菜单中选择[New]-[Static Structure Diagram]即可创建用于制作类结构图的图面了,如果从弹出菜单中选择[New]-[Sequence Diagram]即可创建用于制作时序图的的图面.
设定对象的属性
设定对象的详细信息的大部分操作是通过属性对话框实现的.可以通过在对象上双击鼠标或单击鼠标右键并选择属性属性来表示属性对话框.
几种小技巧
改变连线的方式
在绘图的过程中连线是最常见的操作.象下图那样,线有直角连接线和直线连接线和曲线连接线三种.
可以通过,用鼠标右键点击希望改变种类的连接线,在弹出菜单中选择适当的连接线种类.
扩大和缩小
我想说的不是当然我们可以通过菜单实现扩大和缩小,而是通过按住Ctrl键,在上滚/下滚鼠标的滚轮来实现扩大和缩小.
上下/左右滚动屏幕
除了用鼠标拖动滚动条的方法以外,用鼠标滚轮也可以上下滚动屏幕.那么左右滚动呢,你可能已经猜到了,先按下Shift键就可以了.
拷贝已经存在的对象
首先按下Ctrl键,用鼠标脱动对象,最后释放Ctrl键就可以了.需要注意的Ctrl键释放的时机一定要在鼠标释放之后.
画水平线/垂直线
按下Shift键,在拖动鼠标画线,就可以很简单的画出水平线和垂直线.其实还可以画45度的斜线.
因为类图很直观,所以恐怕C++成员首先接触到的应该就是类图了.在这篇文章中我们要将下面一个在MFC程序中随处可以见到类用UML图表现出来.
class CGraphicObject
{
CRect m_rectBound;
public:
BOOL SetRect(CRect rect);
CRect GetRect();
};
创建类图
在模型资源管理器中选择[Static Model]-[Top Package],点鼠标右键,从弹出菜单中选择[New]-[Static Structure Diagram]即可创建用于制作类结构图的图面了.
准备工作
首先我们遇到的问题是,CRect和BOOL两种类型在Visio数据类型中找不到.所以我们先从追加数据类型开始.为了便于管理我们会先创建MFC数据类型包.
创建数据包
右键点击下图中模型资源管理器的根节点.在弹出菜单中,选择[包]项目.
下图是弹出的包属性对话框.点击[New]按钮,在[UML Package]列中输入[MFC Da
追加BOOL数据类型
在[MFC Da
注意:在MFC中CRect是一个类,但是由于我们并不关心CRect的细节,所以把CRect作为简单数据类型来处理.
追加一个类
追加一个类很简单,然后从形状窗口中的[UML Static Sturcture]分类中拖动[Class]对象就可以了.
设定类的详细信息
设定类的详细信息的大部分工作都是同时属性对话框实现的.对于C++程序员来说,需要设定的内容包括类名,数据成员,成员函数.
以开头提到的类为例。
类名
首先在[Categories]窗口中选择[Class]项目,然后在右面的名称栏目中写入类名就可以了.在这一页中我们可以暂时不必在意其他的内容.
如果只是设定类名的话,大可不必用属性对话框.只要在选中类对象后,再在最上面一栏中单击左键,然后在输入就可以了.
添加数据成员
在[Categories]窗口中选择[Attributes]项目,在右面的画面中增加属性。[Attribute]栏目中写入变量名,[Type]是用来选择数据类型的。这里我们选择[MFC DataTypes::CRect]。[Visibility]栏目选择的是这个成员是公共的(public),保护的(protected)还是私有的(private)。这里我们选择[protected].[Multiplicity]一般翻译成多重性,是指,在类中,数据成员的个数。[1]代表在这个类中,有而且只有一个数据成员。[0..1]表示,没有或者有一个。可以在[Init.Value]中输入数据成员的初值。
增加成员函数
在[Category]窗口中选择[Operations]项目,在右面的表格中追加成员函数。在[Visiblility]中选择函数是,共有,保护还是私有的。[Polymorphic]表示函数是否为多态,也就是使否是虚函数。[Scope]表示一个函数是属于实例(instance)还是属于类(classifier),静态函数,也被称为类的成员函数,普通的成员函数也被称为实例的成员函数。所以如过,在这里选中了[classifier],就说明这个函数是静态函数。
上面的操作,只是设定函数的一些基本信息,更详细的信息可以通过选中函数后,点击[属性]按钮,在出现的[UML Operation Properties]窗口中设定。首先是设定函数的基本信息。和上面的窗口重复的内容,我们不再说明。我们只说明[Profix]和[Suffix]。如果我们想要返回的类型是指针类型或者是应用类型的话,只要在[suffix]中填写[*]或[&]就可以了。
接下来是设定函数的参数。这个函数只有一个参数rect,但是[Parameter]窗口中却出现了,两个参数。不过通过观察[Kind]列的内容可以知道,第一个参数[SetRect]是函数的返回值。第二个[rect]才是我们想要的。这个参数的[Kind]是[in]表明这个参数是用来向函数传递信息的。如果是用来取得信息的,就选择[out],如果是双方向传递信息的,就选择[inout]。
完成上面的工作以后,点击[OK]按钮两次,回到作图画面。来看看我们的成果吧。
前面说明了类结构图的基本画法。要真正要完成实用的类图,还要有许多工作要做。
类之间的关系
继承关系
继承关系是最容易理解的关系。画成图的话就像下面这样。面向对象的说法就是is-a关系。也就是说Class2 is a Class1。在C++中我们说Class2是Class1的派生类,或者说Class1是Class2的基类。
聚集和组成
从容易理解的关系说起.经常有一个类是另一格类的数据成员的情况。在UML中表现为,聚集(aggregation)和组成(composition)。
从图上来看,这两种关系都表现为一端是菱形的直线。其中有菱形的一端是整体,另外一端是部分。区别就是菱形是空心还是实心的。从C++曾序来看的话,如果图画成实心菱形的话,Class1就要负责Class2的创建和销毁。更准确的说,就是如果Class1不存在了,Class2也一定不存在。例如象下面的程序。
class Class2
{
};
class Class1
{
Class2 m_objClass2;
}
当然也有下面的情况
class Class2
{
};
class Class1
{
Class1();
~Class1();
Class2* m_pClass2Obj;
};
光看类的声明就不行了。这是就需要看类的实现部分了。
Class1::Class1()
{
m_pClass2Obj = new Class1;
}
Class1::~Class1()
{
delete m_pClass2Obj;
m_pClass2 = NULL;
}
组成(Composition)关系,如果在Class1的对象销毁的时候,比如在析构函数中没有将数据成员销毁的代码,那么这种关系就是聚集(aggregation)关系。当然,销毁数据成员的代码,会有很多种。
依赖关系
依赖关系就是在以个类中使用了另一个类。例如下面的代码
Class1::DoSomething()
{
Class3 obj;
obj.DoClass3Work();
}
就是这样的情况。画成图的话就像下面这样。