文章目录

  • 案例:房屋中介
  • 代理模式
    • 代理模式与装饰器模式
    • 代理模式的应用
      • 远程代理
      • 虚拟代理
      • 安全代理
      • 智能引用代理
      • 写时拷贝代理
  • 总结
  • 完整代码与文档

由于代理模式相较于前面的其他设计模式来说更加简单,容易理解,所以为了保证内容不会太少,我除了介绍代理模式外还会重点介绍远程代理和虚拟代理,以及简单提及其他的一些代理模式的应用

案例:房屋中介

假设小明准备去外地实习,于是他需要租一间房来居住。

但是由于身在外地,人生地不熟的他根本没办法和正在出租房屋的房东联系,于是他想到了一个好办法,找到具有人脉的房产中介来代替他租房

有了房产中介的加入,小明就可以通过中介来帮助他联系房东,进行租房。

但是此时又面临了一个问题,此时租房的行为是由中介来代为进行的,因此在房东眼里,这间房屋是中介在租,他根本不知道小明的存在。这就导致了一个问题,如果中介翻脸不认账独占房屋,又或者房东有急事要通知小明,那该怎么办呢?

小明让中介代替他去租房,实际租房的人并不是中介,而是小明。因此我们在中介租房的时候,应该清楚的告知房东租房的对象,于是逻辑图变化如下

以行为的角度来说,小明和中介要做的事情都是租房,所以在旁观人眼里,他们两个人都是寻求租房的人,因此我们可以将他们两人都归类为租房者

以代码的角度来实现的话,我们可以将租房者定义为一个接口

class Tenant
{public:virtual ~Tenant() = default;virtual void rentingHouse() = 0;   //租房
};

小明也是租房者,因此他会去实现这个接口

class XiaoMing: public Tenant
{public:void rentingHouse() override{std::cout << "小明需要租房!" << std::endl;}
};

而中介为了让房东知道租房的真实对象,他会保留小明的个人信息(小明对象的引用),并且他除了执行小明的租房任务以外,还会附加新的逻辑(收取佣金),代码如下

class Proxy : public Tenant
{public:Proxy(Tenant* client): _client(client){}void rentingHouse() override{_client->rentingHouse();      //代理行为std::cout << "中介代替客户去租房,并收取佣金" << std::endl; //新增的代理逻辑}private:Tenant* _client;  //代理的客户,需要让目标知道租房的人是谁
};

下面测试一下逻辑是否正确

int main()
{Tenant* xiaoming = new XiaoMing();      //小明Proxy* proxy = new Proxy(xiaoming);     //中介代理小明的租房行为proxy->rentingHouse();  //中介代替客户租房delete proxy, xiaoming;return 0;
}


小明虽然不认识房东,但是他通过中介帮助他租房,上面所描述的这一系列行为,其实就是代理模式


代理模式

代理模式为其他对象提供一种代理以控制(隔离,使用接口)对这个对象的访问

代理模式由以下三部分组成

  • Subject:RealSubject和Proxy的共同接口,利用多态的性质来保证RealSubject能够随时使用Proxy
  • RealSubject:实体,业务逻辑的真实执行者,同时也是Proxy代表的对象。
  • Proxy:代理,保存了实体的引用使其可以访问实体,并且实现了Subject接口,保证其能够随时利用代理来替代实体,并添加新的附加功能

类图如下

从之前所举的例子中,我们不难看出,代理模式的意图就是通过代理实体,来为其附加新的功能。来达到业务逻辑与附加功能的解耦

在上面的例子中,中介为小明代理后,分析需求、寻找房源、联系房东、代替租房,这些行为全都由中介来实现,小明只需要关心租房这件事情,这样我们就达到了解耦合的目的。

如果以工程实践的角度来讲的话,就好比程序员(实体)只需要负责必须的业务功能实现,而对于如:监控、统计、日志等附加的功能就交由运维、数据分析人员(代理)来实现。

但是如果这样理解的话,那么代理模式岂不是和装饰器模式一样,都在为实体对象增加新功能吗?

代理模式与装饰器模式

不了解装饰器模式的可以看看我的往期博客
趣谈设计模式 | 装饰器模式(Decorator):用装饰来动态扩展功能

搬出装饰器模式的类图,我们发现它的结构其实与代理模式非常相似。

装饰器模式使用装饰器来包装实体,而代理模式使用代理来代理实体,他们都是用一个对象将另一个对象包起来,并且把调用委托给实体。并且在这个基础上,他们都为实体附加了新的行为。

但是在前面的博客中我也说过,虽然大体的结构相同,但是这并不意味这这两个设计模式一样,真正决定设计模式的其实是它具体的设计意图

代理模式的核心意图是控制对象的访问代理通过增加与实体类无关的附加行为来达到访问控制的目的

装饰器模式的核心意图是增强对象的功能,通过附加与实体相关的新行为的方式,来增加实体类原本的功能


代理模式的应用

下面讲讲远程代理和虚拟代理,并简单提一下安全代理、智能引用代理、写时拷贝代理

远程代理

远程代理也就是为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实

例如我们借助代理服务器来访问外网的时候,就是使用的远程代理。我们将请求直接发送给代理服务器,而后代理服务器将请求转发到真实服务器并接收服务器的响应,最后代理服务器再将响应的结果归还给我们。这样就仿佛我们直接与真实服务器通信一样。


虚拟代理

虚拟代理,是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象,来达到性能的最优化。

例如我们在网上购物的时候,通常界面上会显示很多商品图片,但是由于图片过多或者图片过大导致加载速度慢,导致图片可能立即无法显示出来。在这段加载的使用中 ,我们就是使用虚拟代理来替代了真实的图片,而虚拟代理中则存储了真实图片的路径

上图中的白框即为虚拟代理,我们会先用它来暂时替代真实图片,并且虚拟代理还会在内部中继续加载真实图片,加载后如下

以代码来实现的话

class Image
{public:virtual ~Image() = default;virtual void display() = 0; //显示图片
};class RealImage : public Image
{public:RealImage(const std::string& imageName): _imageName(imageName){loadImage();    //加载真实图片}void display() override{std::cout << "显示真实图片" << _imageName << std::endl;}void loadImage(){std::cout << "加载真实图片" << _imageName << std::endl;}
private:std::string _imageName;
};class ImageProxy : public Image
{public:ImageProxy(const std::string& imageName): _imageName(imageName), _image(nullptr){}~ImageProxy(){if(_image){delete _image;}}void display() override{/*显示等待语句或者图片*///加载真实图片if(_image == nullptr){_image = new RealImage(_imageName);}_image->display(); //显示真实图片}private:Image* _image;  //真实图片的引用std::string _imageName;    //图片名
};int main()
{Image* proxy = new ImageProxy("test.jpg");proxy->display();  //暂时显示虚拟代理delete proxy;return 0;
}

下面的几种应用比较简单,因此就简单描述一下

安全代理

用来控制对真实对象访问时的权限,通常在对象有不同的访问权限时使用

最典型的应用即防火墙,通过设定黑白名单以及访问权限,来控制对真实对象的访问。

智能引用代理

当真实对象被引用时,代理进行额外的动作

最典型的就是C++中的智能指针中的share_ptr,对于实体资源来说,智能指针就是它的代理。当智能指针第一次引用资源的时候,就会对其进行管理,而当智能指针的生命周期结束,没有智能指针再引用这个资源时,就将这个资源给释放掉。

写时拷贝代理

延迟对象的复制,直到客户真正需要它时
写时拷贝代理其实就是将虚拟代理与引用计数机制相结合,最典型的就是Linux中父子进程的写时拷贝。当父进程创建子进程时,为了避免不必要的拷贝,只有当子进程需要修改数据时,才会将去拷贝父进程的数据,否则继续使用父进程的数据。


总结

  • 代理模式为其他对象提供一种代理以控制对这个对象的访问
  • 代理模式用于控制访问,装饰器模式用于增强功能,两者虽然结构相同,但是意图不同。
  • 将业务逻辑与附加功能解耦合,实体只需要关注自己部分的功能,而不用关心代理所做的事情,职责更加清晰,拓展性更高
  • 在客户端和实体之间增加代理对象,导致请求的处理速度可能会变慢

完整代码与文档

如果有需要完整代码或者markdown文档的同学可以点击下面的github链接
github

趣谈设计模式 | 代理模式(Proxy):利用代理来控制对象的访问相关推荐

  1. 趣谈设计模式 | 策略模式(Strategy):你还在使用冗长的if-else吗?

    文章目录 案例:指挥官AI 策略模式 配合工厂模式 总结 完整代码与文档 案例:指挥官AI 案例可能不符合实际逻辑,仅用于表述设计模式的思想,勿介意 假设我们开发了一款类似全面战争的即时战略游戏,为了 ...

  2. 趣谈设计模式 | 状态模式(State):如何实现游戏中的状态切换?

    文章目录 案例:马里奥积分竞赛 有限状态机 分支逻辑法 查表法 状态模式 状态模式与策略模式 总结 完整代码与文档 案例:马里奥积分竞赛 喜欢马里奥的小伙伴们都应该知道,前不久马里奥为了庆祝35周年, ...

  3. 趣谈设计模式 | 模板方法模式(Template Method):封装不变部分,扩展可变部分

    文章目录 案例:房屋建造 模板方法模式 模板方法模式与策略模式 总结 完整代码与文档 这个设计模式过于简单,所以不是很好举例- 案例:房屋建造 假设我们是建筑公司中的规划者,负责设定建筑方案,在初期我 ...

  4. Java代理模式:如何优雅地控制对象访问?

    文章目录 一.引言 1.1 简介 二.什么是代理模式 2.2 概述 2.3 使用场景 2.4 优缺点 三.静态代理模式 3.1 定义 3.2 实现方式 3.3 示例代码 3.4 优缺点 四.动态代理模 ...

  5. 趣谈设计模式 | 工厂模式(Factory):利用工厂来创建对象

    文章目录 案例:外设店铺 简单工厂 工厂方法 抽象工厂 总结 要点 三类工厂模式的特点 三种工厂模式的适用场景 完整代码与文档 工厂模式模式是创建型模式中较为常用的一个,它并不是一个模式,而是三种功能 ...

  6. 代理模式Proxy——在线代理

    1.问题与模式:怎样在不直接访问网易博客的情况下,发表博客? 时间:2012年某月周日晚             地点:学校机房              人物:学生甲 网易博客都好几天了还是打不开, ...

  7. 趣谈设计模式 | 桥接模式(Bridge):将抽象与实现分离

    文章目录 案例:跨平台应用开发 桥接模式 总结 完整代码与文档 案例:跨平台应用开发 A公司最近准备开发一组应用合集,目前包括了视频播放器.音乐播放器.文本播放器三种应用,但是在发售前,他们遇到了困难 ...

  8. 趣谈设计模式 | 外观模式(Facade):为子系统提供高粒度接口

    文章目录 案例:自动驾驶飞机 外观模式 总结 完整代码与文档 案例:自动驾驶飞机 随着自动驾驶汽车的大卖,特X拉开始把目标转向飞行领域,打算开发出一款能够完全自动行驶的飞机,系统初步的设计如下 我们将 ...

  9. 趣谈设计模式 | 命令模式(Command):将命令封装为对象

    文章目录 案例:智能遥控 命令模式 应用场景 队列请求 日志系统 总结 完整代码与文档 命令模式的应用场景较少,且不易理解,因此我也不好举例,所以下面的描述可能会存在一些问题,请见谅 案例:智能遥控 ...

最新文章

  1. 13 个mod_rewrite 应用举例
  2. mybatis 中#与$的区别
  3. linux 内存 面试,【Linux内存面试题】面试问题:查看机器配置命… - 看准网
  4. Windows10 【系统周期表】【系统下载表】【大型软件表】
  5. linux的常用操作——程序调试gdb
  6. QT学习笔记(四):Qt5+MSVC编译 中文字符显示乱码问题解决
  7. 【Qt串口调试助手】1.7 - QLabel标签插入链接,修改Qt应用图标
  8. float.valueof()自动截取有效位数
  9. css 背景色半透明 子元素不透明
  10. 树莓派 之 动态DNS(DNSPod)
  11. tinyhttpd源码分析
  12. 2021年湖北省区块链技术应用创新创业大赛已正式启动,欢迎报名参赛
  13. 会议panel是什么意思中文_会议形式有哪些?
  14. 对于程序员“中年危机”的一点思考
  15. Java求时间差(日期差)
  16. 自制的MATLAB拼图游戏GUI界面版详解(下篇)
  17. SAP标准功能重复制造计划编制表实现生产排产初步分析
  18. C语言 % x的作用,关于c语言%#X意思大全
  19. iOS10 UICollectionView不调用cellForItemAtIndexPath
  20. 用Vue+Node从零开始实现拼多多前后端商城项目 — 记录踩坑之旅(上篇)

热门文章

  1. 编写Eureka入门案例
  2. Spring Session实战2
  3. 方法重载(overload)和方法重写(override)的比较
  4. mysql 5.7 速度很快_MySQL5.7速度比MySQL5.6快3倍
  5. Java官方相关资源文件的获取教程
  6. 【报错笔记】做struts项目建立jsp文件老是报错
  7. C51_按键按下,流水灯亮起,数码管显示按下的次数
  8. css背景图根据屏幕大小自动缩放
  9. SSIS技巧--优化数据流缓存
  10. 极客班C++ STL(容器)第二周笔记