前前后后犹豫好久,到底是写不写设计模式,毕竟自己不是科班出身,最后还是决定根据大神博客和设计模式之禅写下几种常见的
设计模式,等到后面使用的时候再来复习。不管是跟着什么资料在学习,记住一定要思考,一定要敲代码,一定要升华!!!
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;
//GPS
Cgprs 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");
//测试GPS
person.use(&gps);
cin.get();
return 0;
}
程序测试结果:
写程序的过程中注意几点:
1、注意根据类图定义类的顺序
2、阶段性编译原则
总结:继承 实现(抽象类、接口定义) 依赖(use-a) 关联:语义上是平等的朋友关系
聚合(has-a):整体-部分关系,部分可以脱离整体存在 组合(contain-a):整体-部分关系,部分不能脱离整体。
特定的类之间的关系,在代码层面上可能相同,但是可以在语义上进行区分。所以类之间的关系,需要在特定的环境下进行区分类之间的关系。
通过上面的例子可以更好的了解类之间的关系,有助于进一步理清后面思路。