c++设计模式之代理模式

前言

在某些情况下,客户不能或者不想直接访问一个对象时,可以通过寻找一个中介来帮他完成访问对象的任务。例如自己不愿意去上课时,可以找一个人A代替你去上课,A就扮演了代理者的角色。在软件设计中,代理模式的使用也是为了完成这样的一种机制。

代理模式的定义

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

代理模式的分类

按照代理模式的使用目的,代理模式可以有以下几种形式:
1.远程代理:就是为一个对象在不同的地址空间提供局部代表
2.虚拟代理:在创建一个资源消耗较大的对象之前可以先创建一个资源消耗稍小的对象,真实的对象可以在需要时才会创建
3.保护代理:控制一个对象的访问,可以给不同的用户提供不同级别的访问权限。
4.智能引用代理:当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等。

代理模式的结构

代理模式的UML图如下所示:
在这里插入图片描述
如上图可以看出,代理模式的结构较为简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构和实现方法。
该模式有如下三个角色:
1.抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
2.真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
3.代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
下面我们来看一个简单的例子:
抽象主题类:

class Subject
{
	public:
		virtual void Request() = 0;	//声明了真实主题和代理类的公共接口

真实主题类:

class Real:public Subject
{
	public:
		virtual void Request()//真实主题类的实现
		{
			cout << "I am real" << endl;
		}
};

代理类:

class Proxy:public Subject
{
	private:
		Real* mreal;// 在代理类中声明一个真实主题的成员以便访问真实主题类的接口
	public:
		virtual void Request()
		{
			mreal = new Real();
			mreal->Request();
			delete mreal;
		}
		
};

完整的代码:

#include <iostream>
using namespace std;
class Subject
{
	public:
		virtual void Request() = 0;	
};
class Real:public Subject
{
	public:
		virtual void Request()
		{
			cout << "I am real" << endl;
		}
};
class Proxy:public Subject
{
	private:
		Real* mreal;
	public:
		virtual void Request()
		{
			mreal = new Real();
			mreal->Request();
			delete mreal;
		}
		
};
int main()
{
	Proxy* proxy = new Proxy();
	proxy->Request();
	return 0;
}

这样就实现了一个简单的代理模式。咋一看,好像觉得访问Real的时候通过Proxy去访问,感觉上多此一举,但其实在前面也说过,在代理类中可以起到对真实主题的访问控制功能,例如去银行取钱的时候,插入银行卡还需要输入密码才能取钱。像这样一个场景,真实主题的接口可以不用判断密码的正确与否,只管取钱的功能,而输入密码的正确性则交由代理类去判断即可。
下面我们可以模拟一下银行卡的登录操作。该例子模仿另一位大佬写的qq登录系统,链接如下:
(https://blog.csdn.net/ZYZMZM_/article/details/89530127)

#include <iostream>
#include <cstring>
#include <unordered_map> 
using namespace std;

unordered_map<string,string> UserInfo;//用以保存银行卡id和密码

void addUserInfo(string Id,string pwd)
{
	UserInfo.insert(make_pair(Id,pwd));
}

void delUserInfo(string Id)
{
	UserInfo.erase(Id);
	cout << "Id:" << Id << endl;
}

void show()
{
	cout << "DataBase info:" << endl;
	auto it = UserInfo.begin();
	while(it!=UserInfo.end())
	{
		cout << (*it).first << ":" << (*it).second << endl;
		it++;
	}
	cout << endl;
}

class Subject
{
	public:
		virtual void Request() = 0;
};

class RealSubject:public Subject
{
	public:
		RealSubject(string id,string pwd)
		:mId(id),mpwd(pwd) {}
		virtual void Request()
		{
			cout << mId << ": login ok " << endl;
		}
	private:
		string mId;
		string mpwd;		
};
class ProxySubject:public Subject
{
	private:
		RealSubject *mrealsubject;
		string mId;
		string mpwd;
	public:
		ProxySubject(string id,string pwd)
		:mId(id),mpwd(pwd){}
		bool PreRequest()
		{
			auto it = UserInfo.find(mId);
			if(it!=UserInfo.end()) //判断银行卡号是否存在
			{
				if(strcmp((*it).second.c_str(),mpwd.c_str()) == 0)//判断密码是否正确
				{
					return true;
				}
				else
				{
					cout << mId << ":pwd is not right" << endl;
				}
			}
			else
			{
				cout << mId << ":id is not exist" << endl;
			}
			return false;
		}
		virtual void Request()
		{
			if(PreRequest())
			{//银行卡id和密码都没有问题了才可以调用真实主题的接口登录
				mrealsubject = new RealSubject(mId,mpwd);
				mrealsubject->Request();
				delete mrealsubject;
			}
			else
			{
				cout << "login faild" << endl;
			}
			
		}
		
};

int main()
{
//添加银行卡
	addUserInfo("11","111111");
	addUserInfo("22","222222");
	addUserInfo("33","333333");
	addUserInfo("44","444444");
	addUserInfo("55","555555");
	
	show();
	ProxySubject user1("11","111111");//添加正确的银行卡
	user1.Request();
	//添加不存在的银行卡
	ProxySubject user2("66","111111");
	user2.Request();
	//添加密码错误的银行卡
	ProxySubject user3("22","111111");
	user3.Request();
	return 0;
	
}

运行代码结果如下:
在这里插入图片描述
由上面的例子不难看出代理模式优缺点。代理模式的优点:
1.代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用
2.代理对象可以扩展目标对象的功能
3.代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
缺点:
1.在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢
2.增加了系统的复杂度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值