870920 Menu

SwingCoder之面向对象分析、设计及软件研发·4

UML建模

UML:统一建模语言。UML并非计算机编程语言,而是一种专用于软件系统的分析与设计的可视化图形文字表示方法,尤其适合于OOAD(面向对象分析与设计)和系统建模。UML 2.0定义了13种图示(Diagram),最常用的有3种:类图,用例图,时序图。类图中,类之间的关系有6种:泛化、实现、一般关联、依赖、聚合、组合。前两种为类的继承(is-a),后4种为类的包含(has-a)。

1、泛化关系(Generalization):子类继承非抽象基类,符号为直线和空心箭头。箭头指向基类。
class ChildClass : public BaseClass

图 1 19 Generalization泛化关系(普通继承)

2、实现关系(Realization):子类继承并实现抽象基类,符号为虚线和空心箭头。箭头指向基类。
class ChildClass : public AbstractClass

图 1 20 Realization实现关系(继承抽象基类)

3、一般关联(Association):类的对象之间在概念上有连接关系,但是两个类各自独立,不存在包含关系和依赖性。一般关联的符号为直线和实心箭头。双向关联为一条直线,无箭头。注意:关联关系中有一对多(B中有多个A的对象)和多对一(多个B中皆有A的对象)等多种模式,还包括本类的自关联(B中有本类的指针)。
class ClassA; // ClassB类的头文件中前向声明ClassA类
class ClassB // ClassB类的类定义,数据成员中虽有ClassA的指针,但该对象并不重要
{
// ClassA类的指针可为nullptr,两个类的关系很松散
void doSomething (ClassA* classA);
};

图 1 21 Association一般关联(B中有A,A可为空)

4、依赖关系(Dependency):B类的函数需使用A类的对象或B类的函数创建并返回A类对象,则修改A类会直接影响到B类,即B类依赖于A类对象。一个类的对象向另一个类的对象发送消息,使该类能正常工作,或者一个类的成员函数需要另一个类的对象作为其参数,或者成员函数中调用另一个类的成员函数来实现某个功能等等,这些都是典型的依赖关系。依赖关系的符号为虚线和实心箭头。B依赖于A,则箭头由B指向A。注意,B类的数据成员中并无A类的对象,A类的数据成员中也无B类的对象。

图 1 22 Dependency依赖关系(B依赖于A,或者B的函数将创建A的对象)

5、聚合关系(Aggregation):两个类的对象分别代表整体和部分,但是这两者各自独立,不存在一方消失,另一方也随之消失的问题,“部分”可以隶属于多个“整体”。通常为构造参数或以外部传参的方式获得赋值的数据成员。或者这样理解:B类的成员函数参数中需要A类的对象(接口需要)。聚合关系的符号为空心菱形、直线和实心箭头。B聚合了A,则箭头指向A。
class ClassA; // ClassB类的头文件中前向声明ClassA类
class ClassB // ClassB类的类定义,数据成员中有ClassA的指针,该对象由构造函数传入
{
ClassB (ClassA* a) : classA (a) { } // ClassB的构造参数为ClassA的指针
ClassA* classA;
};

图 1 23 Aggregation聚合关系(B聚合了A。或者说:B中有A,各自独立)

6、组合关系(Composition):最强烈的关联关系(属于部分与整体的关系,但“部分”只能隶属于“整体”),“整体”不存在了,“部分”也随之消失。比如内容组件中的控件,内容组件消失,控件也随之消失。通常,组合而来的对象为:需由本类负责创建、管理并销毁的数据成员。或者这样理解:B类创建、持有并管理A类的对象(实现需要,并且往往是构造函数中创建,析构函数中销毁之)。组合关系的符号为实心菱形、直线和实心箭头(双向可达性无箭头)。B组合了A,则箭头指向A。
#include “ClassA” // ClassB类的头(源)文件中需包含ClassA类的类定义,否则无法创建该类的对象
class ClassB // ClassB类的数据成员中有ClassA的指针,该对象由本类创建和管理
{
public:
// ClassB的构造函数中创建ClassA的堆中对象
ClassB () : classA ( new ClassA() ) { }
// ClassB的析构函数中销毁ClassA的堆中对象
~ClassB () { deleteAndZero(classA); }
private:
ClassA* classA;
};

图 1 24 Composition组合关系(B组合了A。或者说:B中有A,同生共死)

无论是研究源码,还是前期设计,画出类图和时序图都是非常重要的一步。可使用EA、PowerDesigner等UML工具软件这件事。常用的3种图例见下:

1、用例图(Use Case Diagram)

表示用户操作的一种图例。下图中guest可以访问query模块,而Admin则可以访问所有模块。

图 1 25 UML用例图

2、类图(Class Diagram)

比较重要和常用的UML图例,表示整个系统或系统某个模块中类与类之间的关系。

图 1 26 类图

3、时序图(Sequence Diagram)

表示某个函数中的调用过程,特别是该函数中调用了其他类的函数。函数的返回线可不标注。

图 1 27 UML时序图

类图中成员标识符(数据成员的名称和函数名)在左侧,之后是“:”,冒号右侧是函数的返回类型或对象的类型。这么做的意义是:先看看有什么,名字是什么,能做什么,而后是该函数返回什么类型,或者该对象是什么类型的。这种方式虽然与C++中的声明对象、变量和函数的语法顺序相反,但更适合于阅读和理解。成员名字左侧的“+”表示该成员为public属性,“-”为private,“#”为protected。

图 1 28 UML类图示例

对应的C++语句为:
class MyClass
{
public:
void setValue(const int value);
const int getValue();

protected:
void timerCallback();

private:
AudioSource* audioSource;
};