C++设计模式——代理模式(Proxy Pattern)
微信公众号:幼儿园的学霸
目录
定义
The proxy design pattern allows you to provide an interface to other objects by creating a wrapper class as the proxy. The wrapper class, which is the proxy, can add additional functionality to the object of interest without changing the object’s code.
代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。代理模式通俗来讲就是我们生活中常见的中介。
由于某些原因,一个类(A)不能直接被客户端使用,所以我们可以创建这个类的代理类(B),实际上B就是A的影子而已
在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。
代理模式中的角色如下:
- 抽象主题角色(Subject):可以是抽象类,也可以是接口。定义真实主题角色RealSubject 和 抽象主题角色Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使
用Proxy。 - 具体主题角色(RealSubject):也叫做被委托角色或被代理角色,是业务逻辑的具体执行者。定义了代理角色(proxy)所代表的具体对象
- 代理主题角色(Proxy):也叫做委托类或代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在具体主题角色处理完毕前后做预处理和善后处理工作。
其类图如下:
一个代理类可以代理多个被委托者或被代理者,因此一个代理类具体代理哪个具体主题角色,是由场景类决定的。最简单的情况是一个主题类和一个代理类。通常情况下,一个接口只需要一个代理类,具体代理哪个实现类由高层模块决定。
代码示例
以代理服务器为例进行代码编写,访问真正的服务器,需要通过代理服务器,代理服务器进行用户名密码校验,通过才允许访问真实服务器。
#include <bits/stdc++.h>
//抽象类,抽象的主题类
class AbstractServer {
public:
virtual void Request() = 0;
virtual ~AbstractServer() = default;
};
//真正主题类,具体提供服务的类
class RealServer : public AbstractServer {
void Request() override {
std::cout << "服务器启动..." << std::endl;
}
};
//代理服务器,非真正的服务器,访问真正服务器必须通过代理服务器
class ProxyServer : public AbstractServer {
public:
ProxyServer(const std::string &name, const std::string &pwd)
: m_name(name), m_pwd(pwd) {
m_pserver = std::make_shared<RealServer>();
}
// 和 真正主题类实现共同的接口,对外可以提供一致的接口!
void Request() override {
if (!CheckUser()) {
std::cout << "用户名或者密码错误..." << std::endl;
return;
}
std::cout << "校验用户名及密码成功..." << std::endl;
PreRequest();//额外附加的操作
m_pserver->Request();
PostRequest();//额外附加的操作
}
private:
//访问服务器前 进行的动作,可以控制对真实主题类的访问
bool CheckUser() {
if ("admin" == m_name && "123456" == m_pwd) {
return true;
}
return false;
}
//真正访问服务器前 进行的动作
void PreRequest() {
std::cout << "进入代理服务器..." << std::endl;
}
//访问服务器之后 进行的动作
void PostRequest() {
std::cout << "服务器访问完毕..." << std::endl;
}
private:
std::shared_ptr<AbstractServer> m_pserver;
std::string m_name;
std::string m_pwd;
};
//客户端 通过登录代理服务器 访问 真实服务器
int main(int argc, char *argv[]) {
std::shared_ptr<AbstractServer> proxy = std::make_shared<ProxyServer>("admin", "123456");//登录代理服务器
proxy->Request();//通过代理服务器 访问真正服务器
return 0;
//运行结果如下:
//校验用户名及密码成功...
//进入代理服务器...
//服务器启动...
//服务器访问完毕...
}
先访问代理类再访问真正要访问的对象。似乎这样有点多此一举的味道,其实不然。代理类可以在真正的类执行之前,进行预处理。
在比如你有一个系统实现了登陆功能,在用户登录时,真正的登录类和代理登录类都实现了Login接口, 不同的是Proxy类的方法中增加了用户是否合法的判断,只有合法时才去调用真正登录类的login方法. 用户访问的其实是Proxy的login方法.这都是代理模式的优点。而且采用代理模式的话,并且你可以随时更改代理。
总结
优缺点
- 优点:
1.职责清晰。 2.高扩展性。 3.智能化。 - 缺点:
1.由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 2.实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
对比
-
代理模式与外观模式:
1.代理模式中的代理角色和真实角色都继承于同一类。而外观模式是多个类的集合。
2.代理角色与真实角色接口相同,功能一致,代理角色实现的是真实角色的功能。外观者模式的子系统功能不同,根据用户不同需要与外观类统一配置。
3.实现方式上,外观模式是产生一个新类,封装内部操作;代理是产生一个继承类,操作对用户看起来是一样的。 -
代理模式与适配器模式
适配器模式主要改变所考虑对象的接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作,大多用在代码维护的后期,或者借用第三方库的情况下;而代理模式不能改变所代理类的接口。 -
代理模式与装饰模式
装饰器模式为了增强功能,而代理模式是为了加以控制。 (该部分区别在装饰模式有所阐述)
代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是通过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。
智能指针的引用计数实现,应该就是采用代理模式实现的。个人看法。
参考资料
1.代理模式
2.设计模式之——代理模式
3.设计模式:代理模式(C++)【代理服务器案例】