UML语言
为了能够更好的进行面向对象的设计,所以需要引用专门的设计语言,也就是我们的UML语言,Unifed Modeling Language, 又称统一建模语言或标准建模语言,是始于1997年一个OMG(Object Management Group)标准,它是一个模型化和软件系统开发的图形化语言。UML为软件开发提供了一些标准的图例(10种),统一开发思想,从而促进团队协作。这10中图例如下:
这里我们主要的来看红色的两种图例,第一种是类图,描述的是类与类之间的关系,第二种是一种动态图,可以看到一个动态的过程,后面对序列图我们在进一步了解,现在先来学习类图。
类与类之间的关系
我们知道UML中有10中图例,第一种就是类图,也就是描述类与类之间的关系,那类与类之间具备哪些关系呢?在此我们来看看他们之间的五种关系,继承(泛化)、关联、聚合、组合、依赖。
1、继承(泛化)
继承关系,或者泛化关系,描述的是两个类之间一种很强的关系,基类部分会成为派生类的一部分,在语义上是一个A is B的特点。例如经理是个员工、软件开发工程师是个员工、销售也是一个员工,所以可以设计下面的图例:
此例中,派生类经理、软件工程师、销售都是一个职员,体现出了is的关系。如果使用UML语言的话,使用空心三角箭头从派生类指向基类,这种关系其实是一种垂直的关系。
继承与泛化的区别:继承是先有基类,然后从基类产生新的类,也就是派生类;而泛化是先有派生类,然后多个派生类抽出基类,也就是先有派生类,然后才有基类。二者考虑的方向不一样,其实泛化更符合面向对象的思想。
2、关联
关联关系,是两个类之间最简单,最单纯的关系,表明两个类之间是有关系的,试想,如果两个类之间没有关系,那就不能满足面向对象的特点,对象与对象之间进行交互,使得彼此之间的状态发生变化的特点。而关联关系包括两种:双向的关联关系与单向的关联关系。但是不论哪种关联关系,两个类之间彼此并不负责对方的生命周期。注意在语义上是A has B的关系,一种固定的关系。在代码上的表现形式是:使用引用或者指针。两种关联关系的例子:
双向的关联关系(使用直线),客户与订单之间的关系。
单向的关联关系,条件变量与互斥锁(Condition知道MutexLock的存在,但是MutexLock不知道 Condition的存在,使用实线箭头从Condition指向MutexLock)
3、聚合
是一种比较强的关联关系。对象之间的关系表现为整体和局部,整体部分并不负责局部对象的销毁。语义上表现为A has B。代码上表现为:数据成员以指针或者引用形式存在。使用。
4、组合
更强的一种关联关系。对象之间的关系表现为整体和局部,整体部分负责局部对象的销毁。语义上表现为A has B。代码上表现为,数据成员以子对象成员形式存在。使用。
5、依赖
是两个类之间的一种不确定的关系,语义上是一种A use B的关系,这种关系是偶然的,临时的,并非固定的。在代码上表现为:B作为A的成员函数参数;B作为A的成员函数的局部变量(B作为A的成员函数的返回值);A的成员函数调用B的静态方法。使用。
五种关系的总结
类与类之间的这五种关系,是类和类之间的一种普遍关系。
这五种关系,从耦合程度来看的话是:依赖 < 关联 < 聚合 < 组合 < 继承;
从语义上来看,继承是A is B,关联、聚合、组合是A has B,依赖是A use B的关系;
从方向上来看,继承是类与类之间的纵向关系,而其他四种是类与类之间的横向关系。
之前我们实现多态使用的是继承与虚函数这种面向对象的方法,现在知道了类与类之间的其他关系后,可以使用组合与依赖这种基于对象的方法实现。
类的UML画法
类(class / struct)封装了数据和行为,是面向对象的重要组成部分,它是具有相同属性、操作、关系的对象集合的总称。在系统中,每个类都具有一定的职责,职责指的是类要完成什么样子的功能,要承担什么样子的义务。一个类可以有多种职责,但是设计得好的类一般只有一种职责。
比如,我现在定义了猎人类:
class Hunter
{
public:
int m_age = 32;
static int m_times;
string getName()
{
return m_name;
}
void setName(string name)
{
m_name = name;
}
void goHunting()
{
aiming();
shoot();
}
static void saySorry()
{
string count = to_string(m_times);
cout << "Say sorry to every animal " + count + " times!" << endl;
}
protected:
string m_name = "Jack";
void aiming()
{
cout << "使用" + m_gunName + "瞄准猎物..." << endl;
}
private:
string m_gunName = "AK-47";
void shoot()
{
cout << "使用" + m_gunName + "射击猎物..." << endl;
}
};
int Hunter::m_times = 3;
图分为上中下三部分:上层是类名,中间层是属性(类的成员变量),下层是方法(类的成员函数)。
可见性:+
表示public、#
表示protected、-
表示private、__
(下划线)表示static
属性的表示方式:【可见性】【属性名称】:【类型】= { 缺省值,可选 }
方法的表示方式:【可见性】【方法名称】(【参数名 : 参数类型,……】):【返回值类型】
如果我们定义的类是一个抽象类(类中有纯虚函数),在画UML类图的时候,类名需要使用斜体显示。
在使用UML画类图的时候,虚函数的表示方跟随类名,也就是使用斜体,如果是纯虚函数则需要在最后给函数指定=0。
参考资料