C++设计模式之代理(proxy)模式 -- 句柄

代理模式,个人认为用的比较多的实现方式为句柄和伪代理。

一、句柄

所谓句柄,就是可以用一个句柄类对象去操作一个或多个对象,而不用关心操作对象的实现。我们可能对遇到这种情况:对于操作的每种情形,都具有相似或相同的接口,但接口的具体操作不相同,而对于类用户来说,并不想知道你的每种实现类,只想用一个对象和一组接口进行操作。这个时候,比较好的解决方法是句柄。

实例:对一个游戏来说,可能有几种不同的战局模式:正式战PVP、练习战PVP、PVE等。这些战斗类型结算都具有相同的接口,只是具体保存的数据或其他处理不同。而对于战局来说,我只想在结算时调用接口,不想关心这是什么战斗类型。

C++设计模式之代理(proxy)模式 -- 句柄_第1张图片

如图所示,CResultBase为结算基类,定义接口,派生出COfficialResult、CPVEResult、CPracticeResult三个类,分别实现不同战斗类型下数据的处理。定义一个句柄类CSessionResult,开战时传入战斗类型,由该句柄生成具体的战斗结算对象,外界通过这个句柄调用结算接口。实现如下:

SessionResult.h

#ifndef __SessionResult_H_
#define __SessionResult_H_

typedef unsigned __int64 u64;

enum EBattleType
{
	EBT_Official	=	0,
	EBT_PVE			=	1,
	EBT_Practice	=	2,
};

class CResultBase
{
public:
	virtual		~CResultBase(){}

	virtual		void	AddPlayerInfo(u64 PlayerID)	= 0;
	virtual		void	Save()						= 0;
};

class COfficialResult : public CResultBase
{
public:
	COfficialResult() {}

	virtual		void	AddPlayerInfo(u64 PlayerID);
	virtual		void	Save();

private:
	//data
};

class CPVEResult : public CResultBase
{
public:
	CPVEResult() {};

	virtual		void	AddPlayerInfo(u64 PlayerID);
	virtual		void	Save();

private:
	//data
};

class CPracticeResult : public CResultBase
{
public:
	CPracticeResult() {};

	virtual		void	AddPlayerInfo(u64 PlayerID);
	virtual		void	Save();

private:
	//data
};

class CSessionResult
{
public:
	CSessionResult(EBattleType BattleType);
	~CSessionResult();

	CResultBase*	operator->();
	CResultBase&	operator*();

private:
	CResultBase*	m_SessionResult;
};

#endif


CSessionResult.cpp

#include "stdafx.h"
#include "SessionResult.h"
#include <iostream>
#include <assert.h>

using namespace std;

void COfficialResult::AddPlayerInfo(u64 PlayerID)
{
	//do something
	cout<<"Add Player To Official Battle"<<endl;
}

void COfficialResult::Save()
{
	//save data
	cout<<"Save Official Battle Data"<<endl;
}

void CPVEResult::AddPlayerInfo(u64 PlayerID)
{
	//do something
	cout<<"Add Player To PVE Battle"<<endl;
}

void CPVEResult::Save()
{
	//save data
	cout<<"Save PVE Battle Data"<<endl;
}

void CPracticeResult::AddPlayerInfo(u64 PlayerID)
{
	//do something
	cout<<"Add Player To Practice Battle"<<endl;
}

void CPracticeResult::Save()
{
	//save data
	cout<<"Save Practice Battle Data"<<endl;
}

CSessionResult::CSessionResult(EBattleType BattleType)
{
	switch(BattleType)
	{
	case EBT_Official:
		m_SessionResult = new COfficialResult;
		break;
	case EBT_PVE:
		m_SessionResult = new CPVEResult;
		break;
	case EBT_Practice:
		m_SessionResult = new CPracticeResult;
		break;
	default:
		cout<<"Unknown Battle Type"<<endl;
		assert(0);
		break;
	}
	assert(m_SessionResult);
}

CSessionResult::~CSessionResult()
{
	if(m_SessionResult)
		delete m_SessionResult;
}

CResultBase* CSessionResult::operator ->()
{
	return m_SessionResult;
}

CResultBase& CSessionResult::operator *()
{
	return *m_SessionResult;
}


测试

#include "stdafx.h"
#include "SessionResult.h"

int _tmain(int argc, _TCHAR* argv[])
{
	CSessionResult result(EBT_PVE);
	result->AddPlayerInfo(10001);
	result->Save();

	return 0;
}

输出

Add Player To PVE Battle
Save PVE Battle Data


可以看到,只需要在使用句柄时,传入战斗类型,调用时直接使用句柄重载的操作符就可以操作具体的结算类对象。也可以把这里的句柄看成是智能指针,只不过一般这种情形只会有一个句柄对象。

注意:这里的CResultBase定义了virtual的虚构函数,所以在句柄析构时调用 delete m_SessionResult 可以调用派生类析构函数删除派生类对象。如果基类没有定义虚析构函数,则需要将基类指针转化为派生类指针再调用delete操作,否则不会调用派生类析构函数,派生类特有的部分将不能得到释放。

你可能感兴趣的:(设计模式,C++)