概述
与前面介绍的组合模式、外观模式相同,代理模式也是一种结构型设计模式。代理模式非常实用,特别是在需要增强现有对象的功能、控制访问权限或是优化性能的情况下。简单来说,代理模式提供了一个对象来控制对另一个对象的访问。这个"代理",就像一个中介或代表,负责管理客户端与目标对象之间的交互。
房地产中介是现实生活中运用代理模式的一个典型例子:当我们想要购买或租赁房产时,通常会通过一家中介公司来处理;这个中介就是卖方和买方之间的代理,它帮助双方沟通、协商价格、准备文件等。中介的存在,使得交易过程更加便捷,并且提供了额外的服务,比如:市场分析、法律咨询等。

基本原理
代理模式的核心思想是:将对一个对象的操作,委托给另一个对象处理。这使得我们可以在不修改原始对象的前提下,增加新的逻辑、优化性能、加强安全等。代理模式的关键在于透明性,对于客户端来说,它并不知道它实际上是在与代理交互,还是直接与目标对象交互。代理模式主要由以下三个核心组件构成。
1、抽象主题。定义了真实主题和代理共同的接口,确保两者可以被统一使用。
2、真实主题。包含了代理所代表的真实业务逻辑或资源,是最终执行实际工作的对象。
3、代理。持有对真实主题的一个引用,并实现了与抽象主题相同的接口。它负责在适当的时候创建或销毁真实主题实例,并可以在转发请求给真实主题之前或之后,执行额外的操作。
基于上面的核心组件,代理模式的实现主要有以下五个步骤。
1、定义接口。创建一个接口或抽象类,它规定了一组方法。这些方法既可以由真实主题实现,也可以由代理实现。
2、实现真实主题。编写具体的服务类,该类实现了上述定义的接口,并包含了所有的核心业务逻辑。
3、实现代理类。创建代理类,同样实现相同的接口。代理类内部持有一个指向真实主题的引用,当代理接收到客户端请求时,它可以决定是否以及如何将请求转发给真实主题。此外,代理还可以在请求前后执行其他操作,比如:日志记录、权限检查等。
4、配置代理。设置代理实例,使其作为客户端和服务端之间的中介。根据需求,可以选择何时创建真实的主题对象,比如:延迟加载。
5、调用代理。客户端通过代理提供的接口进行交互,由于代理和真实主题共享同一个接口,所以从客户端的角度来看,它们是可以互换使用的。
实战解析
在下面的实战代码中,我们使用代理模式模拟了房地产中介帮助客户购买或租赁房产的实现。
首先,我们定义了一个抽象主题类CEstateInterface。它包含两个纯虚函数SellProperty和BuyProperty,这是房地产交易的基本操作接口。任何继承自CEstateInterface的类,都必须实现这两个方法。
然后,我们实现了真实主题类CRealEstate,继承自CEstateInterface。它简单地输出一条信息到控制台,表示卖出或购买房产的动作。
接下来,我们实现了代理类CEstateProxy,同样继承自CEstateInterface,它持有一个指向真实主题的指针。代理在转发请求给真实主题之前,执行一些额外的操作,比如:权限检查和日志记录。
最后,在main函数中,我们创建了CRealEstate实例和CEstateProxy实例,并使用代理来调用SellProperty和BuyProperty方法。由于代理的存在,这些调用会首先经过代理的额外处理逻辑,然后再到达实际的服务实现。
C++
#include <iostream>
#include <string>
using namespace std;
// 定义抽象主题
class CEstateInterface
{
public:
virtual ~CEstateInterface() = default;
// 卖出房产
virtual void SellProperty(const string& clientName, const string& propertyDetails) = 0;
// 购买房产
virtual void BuyProperty(const string& clientName, const string& propertyDetails) = 0;
};
// 实现真实主题(实际的房地产服务)
class CRealEstate : public CEstateInterface
{
public:
void SellProperty(const string& clientName, const string& propertyDetails) override
{
cout << "Sell property for " << clientName << ": " << propertyDetails << endl;
}
void BuyProperty(const string& clientName, const string& propertyDetails) override
{
cout << "Buy property for " << clientName << ": " << propertyDetails << endl;
}
};
// 实现代理类
class CEstateProxy : public CEstateInterface
{
public:
CEstateProxy(CRealEstate* pRealEstate) : realEstate(pRealEstate) {}
~CEstateProxy()
{
delete m_pRealEstate;
}
// 卖出房产,并添加额外逻辑
void SellProperty(const string& clientName, const string& propertyDetails) override
{
// 在转发请求之前,进行权限检查
if (CheckAccess(clientName))
{
LogActivity("Sell", clientName, propertyDetails);
// 转发请求给真实主题
m_pRealEstate->SellProperty(clientName, propertyDetails);
}
else
{
cout << "Permission denied for " << clientName << " to sell property." << endl;
}
}
// 购买房产,并添加额外逻辑
void BuyProperty(const string& clientName, const string& propertyDetails) override
{
// 在转发请求之前,进行权限检查
if (CheckAccess(clientName))
{
LogActivity("Buy", clientName, propertyDetails);
// 转发请求给真实主题
m_pRealEstate->BuyProperty(clientName, propertyDetails);
}
else
{
cout << "Permission denied for " << clientName << " to buy property." << endl;
}
}
private:
// 模拟权限检查逻辑
bool CheckAccess(const string& clientName)
{
return true;
}
// 记录活动日志
void LogActivity(const string& action, const string& clientName,
const string& propertyDetails)
{
cout << "Logging " << action << " activity by " << clientName <<
" for property " << propertyDetails << endl;
}
private:
CRealEstate* m_pRealEstate;
};
int main()
{
// 创建一个真实的房地产对象及其代理
CRealEstate* pRealEstate = new CRealEstate();
CEstateProxy proxy(pRealEstate);
// 使用代理来操作房地产交易
proxy.SellProperty("John", "House");
proxy.BuyProperty("Jane", "Apartment");
return 0;
}
总结
代理模式允许我们在不修改目标对象的前提下,为其添加新的行为或逻辑,这使得代码更加模块化和易于维护。如果使用虚拟代理技术(比如:懒加载),可以在需要时才创建昂贵的对象,从而节省资源和提高性能。另外,远程代理可以在本地环境中代表远端的服务,使客户端像是在调用本地方法一样与远程服务交互,简化了网络通信。
但引入代理意味着系统中多了一层抽象,对于小型或简单的应用程序来说,这可能会引入不必要的复杂性。尽管代理可以在某些情况下优化性能,但额外的消息传递和处理也会带来一定的性能损耗。