当前位置: 首页 > article >正文

C++设计模式结构型模式———代理模式

文章目录

  • 一、引言
  • 二、代理模式
  • 三、总结

一、引言

代理模式是一种结构型设计模式, 让你能够提供对象的替代品或其占位符。 代理控制着对于原对象的访问, 并允许在将请求提交给对象前后进行一些处理。

它的主要思想就是在客户端和真正要访问的对象之间引入一个代理层。于是,以往客户端对真正对象的访问变成了现在通过代理对象进行访问,代理对象在这里起到了一个中介或桥梁的作用。引入代理对象的主要目的是可以为客户端增加额外的功能、约束或针对客户端的调用屏蔽一些复杂的细节问题。


二、代理模式

代理模式的实质是通过引人一个代理类来为原始类(被代理类)增加额外的能力,这些额外的能力可能是指一些新功能、新服务,也可能是一些约束或限制(例如,只有特定用户才能使用原始类)等。

比如我们通过浏览器访问某个网站,最简单的方式就是在浏览器中输入网站的地址来直接访问。首先可以创建一个基类WebAddr代表要访问的网站,代码如下:

class WebAddr {
public:
	virtual void visit() = 0;
	virtual ~WebAddr(){}
};

再来两个继承于WebAddr的子类。

class WebAddr_Shopping:public WebAddr {
public:
	virtual void visit() override
    {
		//访问该购物网站,可能涉及复杂的网络通信
		cout << "访问WebAddr_Shopping购物网站!" << endl;
	}
	
};
class WebAddr_Video :public WebAddr {
public:
	virtual void visit()override
	{
		//访问该视频网站,可能涉及复杂的网络通信
		cout<< "访问WebAddr_Video视频网站!"<<endl;
	}
};

那么我们在访问时,就可以:

unique_ptr<WebAddr> wb1 = make_unique<WebAddr_Shopping>();
wb1->visit();

上面是直接访问某个网站,那么我们引入一个代理类,让代理类帮助我们访问这些网站:

class WebAddrProxy : public WebAddr {
public:
    WebAddrProxy(std::shared_ptr<WebAddr> addr) : _addr(addr) {}
    
    void visit() override {
        // 可以在此处添加额外的代理逻辑
        cout << "代理访问开始..." << endl;
        _addr->visit();
        cout << "代理访问结束。" << endl;
    }

private:
    std::shared_ptr<WebAddr> _addr; // 使用智能指针
};

上述代码实现了一个叫作WebAddrProxy的网站代理类。注意,它仍旧继承自WebAddr类,该代理类有一个WebAddr智能指针的成员变量,该成员变量的值是通过WebAddrProxy类构造函数的初始化列表得到的,这意味着只要所代表的网站不同,调用WebAddrProxy类的visit成员函数时就会去访问不同的网站。

shared_ptr<WebAddr> shoppingAddr = make_shared<WebAddr_Shopping>();
shared_ptr<WebAddr> videoAddr = make_shared<WebAddr_Video>();

WebAddrProxy shoppingProxy(shoppingAddr);
WebAddrProxy videoProxy(videoAddr);

shoppingProxy.visit(); // 访问购物网站
videoProxy.visit();     // 访问视频网站

从表面上看,引人代理类WebAddrProxy似乎让程序代码变得更加复杂,但实际上,引人代理类能够为原始类(WebAddr_ShoppingWebAddr_Video)增加额外的能力。就以上述范例来说,可以在WebAddrProxy类的visit成员函数中,在代码行 _addr->visit(); 的前后增加很多额外的代码来对网站的访问进行额外的限制,例如访问的合法性检查、流量限制、返回数据过滤,等等。WebAddrProxy类的visit成员函数可以进行如下功能扩充。

在实际应用中,我们也可以针对某个需要代理的类创建一个专门的代理类:

class WebAddr_Shopping_Proxy :public WebAddr {
public:
	virtual void visit() override
	{
		//在这里进行访问的合法性检查、日志记录或者流量限制…
		WebAddr_Shopping* p_webaddr = new WebAddr_Shopping();
		p_webaddr->visit();
		//在这里可以进行针对返回数据的过滤·
		//释放资源
		delete p_webaddr;
	}
};

在这里插入图片描述

代理模式结构

在这里插入图片描述

代理模式一般有三种角色:

  • 抽象主题Subject):该类定义真实主题与代理主题的共同接口,这样,在使用真实主题的地方都可以使用代理主题,但是后面会讲到,因为代理的种类繁多,目的各异,所以代理主题并不一定必须与真实主题有共同的接口甚至抽象主题也不是必须存在的。这里指WebAddr类。
  • 代理主题Proxy):该类内部包含了对真实主题的引用,从而可以对真实主题进行访问。代理主题中一般会提供与真实主题相同的接口(这里指visit),以达到可以取代真实主题的目的。代理主题可以对真实主题的访问进行约束和限制,也能够控制只在必要的时候才创建/删除真实的主题(一般通过在visit中增加额外的代码来实现)。这里指WebAddr_Shopping_Proxy
  • 真实主题RealSubject):定义代理主题所代表的真实对象,真正的业务是在真实主题中实现的,客户端通过代理主题间接访问真实主题中的接口。这里指WebAddr_Shopping类。

引入代理设计模式的定义(实现意图):为其他对象提供一种代理,以控制对这个对象的访问。


三、总结

代理模式的使用方式有很多,延迟初始化 (虚拟代理)。 如果有一个偶尔使用的重量级服务对象, 一直保持该对象运行会消耗系统资源时, 可使用代理模式。 无需在程序启动时就创建该对象, 可将对象的初始化延迟到真正有需要的时候。

访问控制:如果你只希望特定客户端使用服务对象, 这里的对象可以是操作系统中非常重要的部分, 而客户端则是各种已启动的程序 (包括恶意程序), 此时可使用代理模式。 代理可仅在客户端凭据满足要求时将请求传递给服务对象。

代理模式和装饰模式有类似之处,但是这两个模式要解决的问题不同或者说立场不同。代理模式主要是代表真实主题并给真实的主题增加一些新的能力或责任,例如,在这里进行访问的合法性检查、日志记录等,这些功能与真实主题要实现的功能彼此之间可能没有什么相关性,主要是控制对真实主题的访问。而装饰模式是通过引入装饰类来装饰各种构件,为具体构件类增加一些相关的能力,与原有构件能力具有相关性,是对原有构件能力或行为的扩展(增强)。

适配器模式能为被封装对象提供不同的接口;

代理模式能为对象提供相同的接口;

装饰模式则能为对象提供加强的接口。

外观模式与代理的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化。 代理与其服务对象遵循同一接口, 使得自己和服务对象可以互换, 在这一点上它与外观不同。

代理模式能为对象提供相同的接口;

装饰模式则能为对象提供加强的接口。

外观模式与代理的相似之处在于它们都缓存了一个复杂实体并自行对其进行初始化。 代理与其服务对象遵循同一接口, 使得自己和服务对象可以互换, 在这一点上它与外观不同。

装饰和代理有着相似的结构, 但是其意图却非常不同。 这两个模式的构建都基于组合原则, 也就是说一个对象应该将部分工作委派给另一个对象。 两者之间的不同之处在于代理通常自行管理其服务对象的生命周期, 而装饰的生成则总是由客户端进行控制。


http://www.kler.cn/a/386836.html

相关文章:

  • Nuxt.js 应用中的 schema:beforeWrite 事件钩子详解
  • Database Advantages (数据库系统的优点)
  • Ruby编程语言全景解析:从基础到进阶
  • 今日 AI 简报 | 开源 RAG 文本分块库、AI代理自动化软件开发框架、多模态统一生成框架、在线图像背景移除等
  • 【go从零单排】JSON序列化和反序列化
  • 从0开始学习Linux——文件管理
  • 【计网不挂科】计算机网络期末考试——【选择题&填空题&判断题&简述题】题库(3)
  • Unity插件NodeCanvas之行为树的详细教程
  • python--案例练习:加,幂指数
  • 华为私有接口类型hybrid
  • 分布式唯一ID生成(二): leaf
  • 详解Rust标准库:HashSet
  • vue3 + element-plus 的 upload + axios + django 文件上传并保存
  • Spark中的shuffle过程详细
  • 使用AutoMySQLBackup 数据库自动备份
  • 【LeetCode】【算法】146. LRU缓存
  • CSP/信奥赛C++刷题训练:经典信奥数学例题(3):洛谷P1075 :[NOIP2012 普及组] 质因数分解
  • JAVA_冒泡排序
  • 数字身份发展趋势前瞻:身份韧性与安全
  • c语言其实很简单----【数组】
  • Spring WebFlux 核心原理(2-3)
  • Nginx简易配置将内网网站ssh转发到外网
  • 【计网不挂科】计算机网络期末考试(综合)——【选择题&填空题&判断题&简述题】完整题库
  • ArcGIS Pro SDK (二十二)订阅和搜索
  • 算法【Java】—— 动态规划之路径问题
  • 在 PostgreSQL 中,重建索引可以通过 `REINDEX` 命令来完成