第1章 UML基础:类的关系

来源:互联网 发布:山东省软件评测中心 编辑:程序博客网 时间:2024/05/18 10:34

前前后后犹豫好久,到底是写不写设计模式,毕竟自己不是科班出身,最后还是决定根据大神博客和设计模式之禅写下几种常见的

计模式,等到后面使用的时候再来复习。不管是跟着什么资料在学习,记住一定要思考,一定要敲代码,一定要升华!!!

1、类的关系

1.1、继承(is-a)和实现:继承表示父子关系(子类是特殊的父类),实现有点像接口继承。

   

1.2、依赖(use-a):表示一个类要使用(use)另一个类。

(1)、类图

   表示C21要使用C22类型

(2)、三种依赖方式:函数参数或返回值、局部变量和静态成员函数或变量

class C21{public:    //1、使用函数形参和返回值发生依赖关系    C22 test(C22 theC22);    //2、使用局部变量发生依赖关系    void test()    {        C22 theC22; //或C22* theC22 = new C22;                    //离开这个作用域后the22要销毁    }    //3、全局变量或静态变量(函数)发生依赖关系    void test()    {        C22 theC22 = g_C22; //g_C22为全局变量        C22::func();        //使用类的静态成员函数    }};

1.3、关联:是一种平等的、朋友关系。

(1)、双向关联:双方都知道对方的存在,可以使用对方的公有成员变量和函数。

      理解:资源在外部,C31类型 表示的是指向资源的指针。

 a、代码表现:双方拥有对方的一个指针或引用。     

 b、之所以是指针有原因。如果是值(对象)那么就不是关联。因为是值的话,C31对象消失C32对象也会跟着消失。(站在内存的角

度理解,资源分配在哪里)。 组合:整体与部分的关系,而且整体消息部分也会消息,部分不能独立于整体。

(2)、单向关联

   注意依赖和单向关联

a、表示相识关系,指C33知道C34,可以调用C34的公共成员变量和函数

b、代码上表示为C33有C34的指针,而C34对C33一无所知。

(3)、自身关联:自己的内部有一个指向自身的指针或引用

             

1.4、聚合与组合

(1) 聚合:(has-a),表示整体-部分的关系,但部分可以脱离整体而单独存在。

         关联是平等的朋友关系。  聚合:整体和部分的关系

a、如C41聚合C42,但是C42可以离开C41而独立存在。在创建C41类的对象时,一般不会马上创建C42对象,而是等待一个外界的

对象传给它。 资源在外部。

b、当用C++代码来描绘关联和聚合时,都是一个类包含了另外一个类的指针。但是他们是有区别的,这个区别不是C++语法上的差

别,而是语义上的差别聚合是整体和部分的关系,而且关联是平等的朋友关系,比如。张三和李四,是关联。而张三和张三的杯

是聚合。张三和张三的鼻子是组合。

(2)、组合(contains-a):表示整体部分关系,但是部分不能脱离整体单独存在。  如:手脚是身体的一部分,轮子与汽车。

   

a、组合用的是值对象(外部传入的,生命周期与整体一样)

b、聚合是指针。但有时组合也可以用指针,在构造函数中创建对象,析构函数中销毁对象

  区别:聚合,一般其对象指针由类外传入的,而组合是在类内部的构造函数中new出来的。

c、从语义上看,组合与聚合也是不一样的。当表示聚合时,部分可以脱离整体。而组合不行。

2、依赖和聚合/组合、关联的区别

(1)、聚合与组合

a、聚合与组合都是一种整体和部分的关系。(脱离能不能存在)

b、部件的生命周期不同

  聚合关系中,整件不会拥有部件的生命周期,所以整件删除时,部件不会被删除。再者,多个整件可以共享同一个部件。

  组合关系中,整件拥有部件的生命周期,所以整件删除时,部件一定会跟着删除。而且,多个整件不可以同时间共享同一个部件。

c、聚合关系是“has-a”关系,组合关系是“contains-a”关系。

(2)关联和聚合

a、表现在代码层面,和关联关系是一致的,只能从语义级别来区分。

b、关联和聚合的区别主要在语义上,关联的两个对象之间一般是平等的,例如你是我的朋友,聚合则一般不是平等的。

c、关联是一种结构化的关系,指一种对象和另一种对象有联系。

d、关联和聚合是视问题域而定的,例如在关心汽车的领域里,轮胎是一定要组合在汽车类中的,因为它离开了汽车就没有意义

了。但是在卖轮胎的店铺业务里,就算轮胎离开了汽车,它也是有意义的,这就可以用聚合了。

(3)、关联和依赖

a、关联关系中,体现的是两个类、或者类与接口之间语义级别的一种强依赖关系,比如我和我的朋友;这种关系比依赖更强、不

存在依赖关系的偶然性、关系也不是临时性的,一般是长期性的,而且双方的关系一般是平等的。

b、依赖关系中,可以简单的理解,就是一个类A使用到了另一个类B,而这种使用关系是具有偶然性的、临时性的、非常弱的,但

是B类的变化会影响到A。

(4)、注意:

上述的几种关系(依赖、关联、聚合/组合)在代码中可能以指针、引用、值等的方式在另一个类中出现,不拘于形式,只有配合

义,结合上下文来判断。而只给出一段代码让我们来判断是什么关系,还是无法准确判断的。

(5)、所谓的这些关系只是在某个问题域才有效,离开了这个问题域,可能这些关系就不成立了。

这几种关系都是语义级别的,所以从代码层面并不能完全区分各种关系。

总的来说关系的强弱程度:组合>聚合>关联>依赖

3、类关系实例分析

(1)、类图

  

(2)、代码实现

//Cgprs.h和Cgprs.c  

#ifndef __CGPSReceiver_H__#define __CGPSReceiver_H__class Cgprs{public:void navigate(void);};#endif#include "Cgprs.h"#include <iostream>using namespace std;void Cgprs::navigate(void){cout << "开始使用GPRS导航..." << endl;}
//CEngine.c和CEngine.h

#ifndef __CENGINE_H__#define __CENGINE_H__class CEngine{private:int mCapacity;int mPower;public:CEngine(int capacity, int power);~CEngine();void start();void stop();int getCapacity() const; //不能修改成员变量的值void setCapacity(int capacity);int getPower() const;void setPower(int power);};#endif#include "CEngine.h"#include <iostream>using namespace std;//尽量使用初始化列表成员变量初始化CEngine::CEngine(int capacity, int power) : mCapacity(capacity), mPower(power){}CEngine::~CEngine(){}void CEngine::start(){cout << mCapacity << "cc,";cout << mPower << "马力的发动机发动了!\n" << endl;}void CEngine::stop(){cout << "发动机关闭了!\n" << endl;}int CEngine::getCapacity() const{return mCapacity;}void CEngine::setCapacity(int capacity){mCapacity = capacity;}int CEngine::getPower() const{return mPower;}void CEngine::setPower(int power){mPower = power;}

//CWheel.c和h文件

#ifndef __CWHEEL_H__#define __CWHEEL_H__#include <string>using namespace std;class CWheel{private:int mNo; //数量int mSize; //尺寸string mTypeName; //类型void check(); //出场检查public:CWheel();CWheel(int no, int size, string TypeName); //构造函数CWheel(const CWheel& cw); //拷贝构造函数CWheel& operator= (const CWheel& cw); //赋值构造函数};#endif#include "CWheel.h"#include <iostream>using namespace std;CWheel::CWheel(){}CWheel::CWheel(int no, int size, string TypeName) : mNo(no), mSize(size), mTypeName(TypeName){check();}CWheel::CWheel(const CWheel& cw){mNo = cw.mNo;mTypeName = cw.mTypeName;mSize = cw.mSize;}CWheel& CWheel::operator= (const CWheel& cw){if (this == &cw)  return *this;mNo = cw.mNo;mTypeName = cw.mTypeName;mSize = cw.mSize;return *this;}void CWheel::check(){cout << "检查第" << mNo + 1 << "个车轮:型号(" << mTypeName << "),";cout << "大小(" << mSize << ")" << endl;}
//CVehicle.c和.h

#ifndef __CVEHICLE_H__#define __CVEHICLE_H__#include <string>#include "CWheel.h"using namespace std;//交通工具类可以实现为接口,抽象类class CVehicle{protected:string mColor;string mMake;int mTopSpeed;CWheel mWheel; //车轮与CVehicle是组合关系,声明为值对象public:CVehicle();void speedup();void slowdown();void start();void stop();};#endif#include "CVehicle.h"#include <iostream>using namespace std;CVehicle::CVehicle(){}void CVehicle::speedup(){cout << "正在加速..." << endl;}void CVehicle::slowdown(){cout << "正在减速..." << endl;}void CVehicle::start(){cout << "车子开始启动..." << endl;}void CVehicle::stop(){cout << "车子停下..." << endl;}
//CCar.c和.h文件

#ifndef __CCAR_H__#define __CCAR_H__#include "CEngine.h"#include "Cgprs.h"#include "CVehicle.h"class CCar : public CVehicle{protected:CEngine mEngine;      //发动机与CCar类是组合关系,声明为值关系Cgprs* mGPSReceiver;  //导航与CCar是聚合关系,声明为指针,由外部传入public:CCar(string color, string make, int speed, Cgprs* gps);~CCar();void drive();};#endif#include "CCar.h"#include <iostream>using namespace std;CCar::CCar(string color, string make, int speed, Cgprs* gps) : mEngine(0, 0){mColor = color;mMake = make;mTopSpeed = speed;mEngine.setCapacity(mTopSpeed + 1000);mEngine.setPower(mTopSpeed - 70);cout << mColor << mMake << "车,最高时速:" << mTopSpeed << endl;mGPSReceiver = gps;mWheel = CWheel(1, 36, "A型汽车车轮");}CCar::~CCar(){}void CCar::drive(){if (mGPSReceiver){mGPSReceiver->navigate();}mEngine.start();speedup();cout << "汽车行驶中..." << endl;slowdown();mEngine.stop();stop();}

//CBicycle.h和.c

#ifndef __CBICYCLE_H__#define __CBICYCLE_H__#include "CVehicle.h"using namespace std;class CBicycle : public CVehicle{public:CBicycle();~CBicycle();void ride();};#endif#include "CBicycle.h"#include <iostream>using namespace std;CBicycle::CBicycle() : CVehicle(){mColor = "白色";mMake = "永久";mTopSpeed = 20;cout << mColor << mMake << "自行车,最高时速:" << mTopSpeed << endl;mWheel = CWheel(1, 21, "B型自行车车轮"); //赋值构造函数  赋值式  调用构造函数临时对象//mWheel(CWheel(1, 21, "B型自行车车轮")); //拷贝构造  定义式}CBicycle::~CBicycle(){}void CBicycle::ride(){start();speedup();cout << "自行车行驶中..." << endl;slowdown();stop();}
//CPerson.c和.h
#ifndef _CPERSON_H_#define _CPERSON_H_#include "Cgprs.h"#include "CBicycle.h"#include "CCar.h"class CPerson{public:Cgprs *mGPSReceiver;            //CGPSReceiver与CPerosn是关联关系(平等、朋友关系),由类外传入void drive(CCar* car);          //CCar与CPerson通过形参发生依赖关系void ride(CBicycle* bicle);     //CBicycle与CPerson通过形参发生依赖关系void use(Cgprs* gps);           //将gps传给mGPSReceiver};#endif #include "CPerson.h"void CPerson::drive(CCar* car){car->drive();}void CPerson::ride(CBicycle* bicycle){bicycle->ride();}void CPerson::use(Cgprs* gps){mGPSReceiver = gps;mGPSReceiver->navigate();}
//main.c

#include <iostream>#include "CPerson.h"using namespace std;int main(void){CPerson person;//GPSCgprs gps;//cout << (void*)(&gps) << endl;//开车CCar* car = new CCar("黑色", "红旗", 200, &gps);person.drive(car);delete car;printf("\n");//骑自行车CBicycle *bicycle = new CBicycle();person.ride(bicycle);delete bicycle;printf("\n");//测试GPSperson.use(&gps);cin.get();return 0;}

程序测试结果:



写程序的过程中注意几点:

1、注意根据类图定义类的顺序

2、阶段性编译原则


总结:继承  实现(抽象类、接口定义)  依赖(use-a)  关联:语义上是平等的朋友关系

    聚合(has-a):整体-部分关系,部分可以脱离整体存在    组合(contain-a):整体-部分关系,部分不能脱离整体。

特定的类之间的关系,在代码层面上可能相同,但是可以在语义上进行区分。所以类之间的关系,需要在特定的环境下进行区分类之间的关系。

通过上面的例子可以更好的了解类之间的关系,有助于进一步理清后面思路。     

0 0