善事利器
----面向对象的工具之牛刀小试
作者:HolyFire
首先先要介绍的是
UML----统一建模语言,它是一种开放的标准建模语言,我要介绍的是它在类视图中的有关的部分,也就是UML中类的图示法。
Rational Rose----使用UML的工具,可以在Rational公司的网站上免费得到,2000版的50M大小,获得它的连接是ftp://ftp.rational.com/public/rose/rose2000win/rose2000ENT/releases/RationalRose2000EnterpriseEdition.exe
不管是用面向对象还是面向过程,我们都需要工具来让我们做的更好。在我们用C++编程的时候,面对一大堆的class,public等等时候能保持清醒的头脑来理清他们的关系呢。我们是否能想象他们是什么呢,人的精力总是有限的,人总是喜欢偷懒的,我们需要的不是对面向对象编程的厌倦,而是更加轻松方便的途径。
公欲善其事,必先利其器。有一个好的工具往往使人事半功倍,我说这句话的目的想告诉大家,我现在不是在做广告,而是向大家推荐一个不错的工具。
该图示法将类分成了三部分
一:头 ----用来表示类的名称
二:信息----用来表示类的属性
三:行为----用来表示类的方法
每个属性/方法前面还有一个小图标,表示他们的可视性,和C++中的private,public和protected相对应。
在C++里声明属性的时候,当然要给出类型,一个方法(也就是函数)
上面的图示对应的C++代码就是
class Class{
private:
int Attrib;
public:
int Operation( int arg = 0 );
};
在Rational Rose工具中,你可以很轻松的就做完这些工作,输入类的名称,类的属性和方法,然后双击类,修改属性的类型和方法的参数和返回值类型,点上几个单选框,按下确定,那么上面图中显示的画面就出现了。
然后呢,你选定菜单Tools -> C++ -> Code Generation后将会生成两个文件,Class.h和Class.cpp,让我们打开它看看都有些什么。
去除了一些别的信息后,留下了我们关心的内容。
Class.h的内容
#ifndef Class_h
#define Class_h 1
class Class
{
public:
//## Constructors (generated) //这是一个缺省构造函数
Class();
Class(const Class &right); //这是一个拷贝构造函数
//## Destructor (generated) //这是一个析构函数
~Class();
//## Assignment Operation (generated)
Class & operator=(const Class &right); //这是赋值拷贝函数
//## Equality Operations (generated)
int operator==(const Class &right) const; //这是一个等值比较函数
int operator!=(const Class &right) const; //不等值比较函数
//## Other Operations (specified)
int Operation (int arg = 0); //我们定义的函数
private:
//## Get and Set Operations for Class Attributes (generated)
const int get_Attrib () const; //读我们定义的属性的函数
void set_Attrib (int value); //写我们定义的属性的函数
private: //## implementation
// Data Members for Class Attributes
int Attrib; //我们定义的属性
};
// Class Class
//读我们定义的属性的函数的实体
inline const int Class::get_Attrib () const
{
return Attrib;
}
//写我们定义的属性的函数的实体
inline void Class::set_Attrib (int value)
{
Attrib = value;
}
#endif
Class.cpp的内容
// Class
#include "Class.h"
// Class Class
//缺省构造函数的实体
Class::Class()
{
}
//拷贝构造函数的实体
Class::Class(const Class &right)
{
}
//析构函数的实体
Class::~Class()
{
}
//赋值拷贝函数的实体
Class & Class::operator=(const Class &right)
{
}
//等值比较函数的实体
int Class::operator==(const Class &right) const
{
}
//不等值比较函数的实体
int Class::operator!=(const Class &right) const
{
}
//自定义的函数Operation的实体
int Class::Operation (int arg)
{
}
你可以设置一下生成类的选项来去掉一些你不想要的东西或者加上你想要的。其实运用这个工具的目的并非它能够自动生成代码,事实上你看到的东西要比上面列出来的多很多,如果你不想把代码转回到Rational Rose工程中的类图,那些附加物真是累赘。
但是好处在于,我们可以一目了然的看到类中有什么属性和方法,你可以仔细的思考来考虑他们的设计和取舍,整个类的构造可视化了。
现在我们已经会用UML图示法表示一个简单的类了。
虚函数在C++中是一个重点,如何在UML图示法中表示一个有虚函数的类呢。
在Rational Rose工具中,我们双击Class图标,在Operations栏双击Operation,在C++栏将OperationKind改成Virtual确认,就是如此而已。
让我们看看生成的代码
Class.h
#ifndef Class_h
#define Class_h 1
class Class
{
public:
//## Constructors (generated)
Class();
Class(const Class &right);
//## Destructor (generated)
~Class();
//## Assignment Operation (generated)
Class & operator=(const Class &right);
//## Equality Operations (generated)
int operator==(const Class &right) const;
int operator!=(const Class &right) const;
//## Other Operations (specified)
//## Operation: Operation%3BE1E77E0237
virtual int Operation (int arg = 0);
};
// Class Class
#endif
那么有人要问了,如何定义静态成员变量呢,我以前介绍过这是一个很有用的技术。当然不会令大家失望了,下面就介绍一下如何表示静态成员变量。
看到了吗,多了一个$符号,哇,这也未免太简单了吧,不过难道复杂一点好吗?
同样的,在Rational Rose工具中,我们双击Class图标,在Attributes栏双击Attrib,在Detail栏点选Static就可以了。
为了看的清楚点,这次我去掉了其他信息。
Class.h
#ifndef Class_h
#define Class_h 1
class Class
{
private: //## implementation
// Data Members for Class Attributes
static int Attrib;
};
#endif
现在该是继承上场的时候了。让我们看看UML图示法如何表示一个类与类的继承关系
那就是,子类用一个空心的箭头指向父类而已。
但是UML并没有标示出继承是private,public,protected中的哪一种,所以只好自己标注一下了。
在Rational Rose工具中我们拖出两个class放到类视图中,命名为A和B,拖出一个Generalization从B指向A即可,在箭头上按右键,发现有Public inheritance,Private inheritance,Protected inheritance可选,还有可以复选Virtual inheritance。
让我们看看生成的代码是什么样的呢
#ifndef B_h
#define B_h 1
// A
#include "A.h"
class B : public A //## Inherits: <unnamed>%3BE1EFB0039D
{
};
#endif
太容易了。
很好我们继续看看关联中的聚合在UML里如何表示吧
弱聚合的意思就是A包含B的一个指针,他们的关系不是很密切,A创建和销毁的时候与B无关。
强聚合的意思就是A包含B的一个实体,A创建的时候B跟着创建,A销毁的时候,B也不存在了。
还是让我们看看生成的代码,事实往往更让人信服。
弱聚合时
A.h
#ifndef A_h
#define A_h 1
// B
#include "B.h"
class A
{
//## Get and Set Operations for Associations (generated)
//## Association: <unnamed>%3BE1F3BB0250
//## Role: A::<the_B>%3BE1F3BD02AD
const B * get_the_B () const;
void set_the_B (B * value);
private: //## implementation
// Data Members for Associations
B *the_B;
};
// Class A
inline const B * A::get_the_B () const
{
return the_B;
}
inline void A::set_the_B (B * value)
{
the_B = value;
}
#endif
强聚合时
A.h
// B
#include "B.h"
class A
{
private: //## implementation
// Data Members for Associations
//## Association: <unnamed>%3BE1F3BB0250
//## begin A::<the_B>%3BE1F3BD02AD.role preserve=no public: B { -> VHgN}
B the_B;
};
// Class A
inline const B A::get_the_B () const
{
return the_B;
}
inline void A::set_the_B (B value)
{
the_B = value;
}
#endif
现在让我们来看一个问题,一个人可以使用各种各样的工具,而工具可以被各种各样的人用,很明显,这是一个多对多的关系,仅仅用关联不能很好的解决这个问题,解决的办法是增加一个关联类,他确定在一个关系中的某个时刻,一个人对应一个工具。
看看生成的代码是什么?
HowManUseTool.h
#ifndef HowManUseTool_h
#define HowManUseTool_h 1
class Tool;
class Man;
class HowManUseTool
{
public:
String DoIt ();
const Tool * get_the_Tool () const;
void set_the_Tool (Tool * value);
const Man * get_the_Man () const;
void set_the_Man (Man * value);
private: //## implementation
Tool *the_Tool;
Man *the_Man;
};
// Class HowManUseTool
inline const Tool * HowManUseTool::get_the_Tool () const
{
return the_Tool;
}
inline void HowManUseTool::set_the_Tool (Tool * value)
{
the_Tool = value;
}
inline const Man * HowManUseTool::get_the_Man () const
{
return the_Man;
}
inline void HowManUseTool::set_the_Man (Man * value)
{
the_Man = value;
}
#endif
HowManUseTool.cpp
#include "HowManUseTool.h"
#include "Tool.h"
#include "Man.h"
String HowManUseTool::DoIt ()
{
}
我们要做的就是在
String HowManUseTool::DoIt ()
{
//加上一句
return the_Man->Who() + " use the " + the_Tool->What();
}
好了,到现在我们讲了一大堆运用UML图示法来进行面向对象设计的方法了,应该是让读者自己消化理解的时候了。
2001/10/28
丁宁