【设计模式】第七章:代理模式详解及应用案例

news2024/12/23 20:03:15

系列文章

【设计模式】七大设计原则
【设计模式】第一章:单例模式
【设计模式】第二章:工厂模式
【设计模式】第三章:建造者模式
【设计模式】第四章:原型模式
【设计模式】第五章:适配器模式
【设计模式】第六章:装饰器模式
【设计模式】第七章:代理模式
【设计模式】第八章:桥接模式
【设计模式】第九章:外观模式 / 门面模式
【设计模式】第十章:组合模式
【设计模式】第十一章:享元模式
【设计模式】第十二章:观察者模式
【设计模式】第十三章:模板方法模式
【设计模式】第十四章:策略模式
【设计模式】第十五章:责任链模式
【设计模式】第十六章:迭代器模式
【设计模式】第十七章:状态模式
【设计模式】第十八章:备忘录模式
【设计模式】第十九章:访问者模式
【设计模式】第二十章:解释器模式
【设计模式】第二十一章:命令模式
【设计模式】第二十二章:中介者模式


文章目录

  • 系列文章
  • 一、定义
  • 二、角色分类
  • 三、UML图
  • 四、实现方式
    • 需求分析
    • 具体实现
      • **简单实现**
      • **动态代理**
  • 五、应用场景
  • 六、优缺点
    • **优点**
    • 缺点


一、定义

摘自百度百科: 所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。


二、角色分类

抽象主题角色(Subject)

定义了代理角色和真实主题角色的共同接口,代理角色通过该接口调用真实主题角色的方法。

真实主题角色(Real Subject)

实现了抽象主题角色的接口,代表真实的业务对象。

代理角色(Proxy)

实现了抽象主题角色定义的接口,并持有真实主题角色的引用,代表了真实主题角色的代理。在代理角色中,可以添加额外的功能,如记录日志、权限控制等,而这些功能并不是真实主题角色本身所具备的功能

客户(Client)

具体调用代理者的角色


三、UML图

UML


四、实现方式

需求分析

假如我们有一个这样的场景:我们想要去看电影,但是我们嫌麻烦不想去电影院排队买票,这时候我们可以选择第三方的平台来买票,并且代理会为我们处理一切的购票相关的事务,包括选座、付款等。其实这种模式就相当于我们设计模式中的代理模式,其代理第三方平台,接下来我们用代码来实现一下这个业务。

具体实现

简单实现

抽象主题角色(Subject)

public interface Subject {
  void request();
}

真实主题角色(Real Subject)

public class RealSubject implements Subject {
  public void request() {
    System.out.println("RealSubject: 处理请求中");
  }
}

代理角色(Proxy)

public class Proxy implements Subject {
  private RealSubject realSubject;

  public void request() {
    if (null == realSubject) {
      realSubject = new RealSubject();
    }
    preRequest();
    realSubject.request();
    postRequest();
  }

  private void preRequest() {
    System.out.println("Proxy: 请求前执行逻辑");
  }

  private void postRequest() {
    System.out.println("Proxy: 请求后执行逻辑");
  }
}

客户角色(Client)

public class Client {
  public static void main(String[] args) {
    Subject subject = new Proxy();
    subject.request();
  }
}

运行结果

Proxy:请求前执行逻辑
RealSubject: 处理请求中
Proxy: 请求后处理逻辑

动态代理

我们有一个接口 Subject 和其一个实现类 RealSubject,我们要使用JDK的动态代理来生成一个代理对象Proxy,代理对象的调用会转发给RealSubject对象。

抽象主题角色(Subject)

public interface Subject {
  void request();
}

真实主题角色(Real Subject)

public class RealSubject implements Subject {
  @Override
  public void request() {
    System.out.println("RealSubject: 处理请求中");
  }
}

动态代理角色(DynamicProxy)

public class DynamicProxy implements InvocationHandler {
  private Object realObject;

  public DynamicProxy(Object realObject) {
    this.realObject = realObject;
  }

  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 调用前执行
    System.out.println("DynamicProxy: 请求后执行逻辑");

    // 执行实际方法
    Object result = method.invoke(realObject, args);

    // 调用后执行
    System.out.println("DynamicProxy: 请求后执行逻辑");

    return result;
  }
}

客户角色(Client)

public class Client {
  public static void main(String[] args) {
    // 创建被代理对象
    RealSubject realSubject = new RealSubject();

    // 创建代理对象
    Subject proxy = (Subject) Proxy.newProxyInstance(
      realSubject.getClass().getClassLoader,
      realSubject.getClass().getInterfaces(),
      new DynamicProxy(realSubject)
    );

    // 调用代理对象的方法
    proxy.request();
  }
}

运行结果

DynamicProxy: 请求前执行逻辑
RealSubject: 处理请求中
DynamicProxy: 请求后执行逻辑

在上述代码中,RealSubject表示真实的业务实现类,DynamicProxy表示动态代理类,Client表示客户端。我们通过创建RealSubject对象,然后创建一个代理对象proxy来访问RealSubject

在代理对象中,我们实现了InvocationHandler接口,并重写了其中的invoke()方法,在调用代理对象的方法时,invoke()方法会被自动调用。在invoke()方法中,我们可以进行一些额外的操作,比如在调用实际对象的方法前后添加日志等。

使用Proxy.newProxyInstance()方法来创建代理对象。该方法需要传入三个参数:ClassLoader对象,Class对象数组和InvocationHandler对象。其中,ClassLoader对象用于加载代理类,Class对象数组表示代理类需要实现的接口列表,InvocationHandler对象用于处理代理对象的方法调用。


五、应用场景

以下部分内容摘自菜鸟教程

意图: 为其他对象提供一种代理,以控制对这个对象的访问。

主要解决: 解决了在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。

何时使用: 想在访问一个类时做一些控制。

如何解决: 增加中间层。

关键代码: 实现与被代理类组合。

应用实例:

  1. Windows中的快捷方式
  2. 猪八戒去找高翠兰,结果却是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒在访问高翠兰的时候看不出来这个是悟空,所以此时孙悟空是高翠兰的代理类
  3. 买火车票不一定在火车站买,也可以去代售点
  4. 一张支票或银行存单是账户中资金的代理。支票在市场交易中用来替代现金,并提供对签发账号上资金的控制
  5. Spring AOP

适用场景:

按职责划分通常有以下场景:

  1. 远程代理
  2. 虚拟代理
  3. Copy-on-Write代理
  4. 保护(Protect or Access)代理
  5. Cache代理
  6. 防火墙(Firewall)代理
  7. 同步化(Synchronization)代理
  8. 智能引用(Smart Reference)代理

注意事项:

  1. 和适配器模式区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口
  2. 与装饰器的区别:装饰器模式为了增强功能,而代理模式是为了加以控制

六、优缺点

优点

  1. 职责清晰
  2. 扩展性高
  3. 智能化

缺点

  1. 由于在客户端和真实主题中间加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢
  2. 实现代理模式需要额外的工作,有些代理模式的实现非常复杂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/721912.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二叉树 — 折纸问题

题目: 一道Google真实出现过的面试题 将一段纸条放在桌上,然后从纸条下边向上方对折1次,压出折痕后展开,此时折痕是凹下去的(称为凹折痕),即折痕凸起的方向指向纸条的背面。如果从纸条的下边向上…

CodeForces..碰撞字符.[简单].[遍历求最大连续]

题目描述&#xff1a; 题目解读&#xff1a; 输入仅由<和>组成的字符串s&#xff0c;给定数组a&#xff0c;a满足 a[i] 和 a[i1] 之间的比较运算符为 s[i] 给出字符串a中不同字符的最小个数。 解题思路&#xff1a; 判断字符<和>的最大连续次数即可&#xff0c;…

MySQL注入-SQLi-Less1笔记

前置知识点&#xff1a; 1. SELECT 1,2,3 用于查询数据通道的方式 例如Less-1中,Secury数据库中的users表结构如下&#xff0c;可以看到有散列&#xff0c;当用户在页面输入id的时候&#xff0c;会查询到对应的散列数据也就是<id>/<username>/<password>&a…

复健练习1—取模与快速幂

复建练习1—取模与快速幂 A&#xff0c;poj3070 没啥可说的&#xff0c;就是裸的矩阵快速幂 #include <algorithm> #include <iostream> #include <cstring> #include <cmath> #include <iomanip>using namespace std; typedef long long ll;…

微服务: 03-rabbitmq在springboot中如何使用(下篇)

目录 前言: 上文传送 4.六大模式实际操作(续) 4.4 路由模式: ---> 4.4.1 消费者配置类 ---> 4.4.2 消费者代码 --->4.4.3 生产者代码 4.5 主题模式: (路由升级版) ---> 4.5.1 消费者配置类 ---> 4.5.2 消费者代码 ---> 4.5.3 生产者代码 ---&g…

【大语言模型】15分钟快速掌握LangChain以及ChatGLM

10分钟快速掌握LangChain LangChain简介LangChain中的核心概念1. Components and Chains2. Prompt Templates and Values3. Example Selectors4. Output Parsers5. Indexes and Retrievers6. Chat Message History7. Agents and Tookits LangChain的代码结构1. LangChain中提供…

Ubuntu学习笔记(一)——目录与路径

文章目录 前言一、相对路径与绝对路径1.绝对路径&#xff08;absolute&#xff09;2.相对路径&#xff08;relative&#xff09; 二、目录相关操作命令1.cd(change directory, 切换目录)2.pwd(print working directory, 显示目前所在的目录)3.mkdir(make directory, 建立新目录…

Versioning data and models for rapid experimentation in machine learning

翻译博客&#xff1a;https://medium.com/pytorch/how-to-iterate-faster-in-machine-learning-by-versioning-data-and-models-featuring-detectron2-4fd2f9338df5 在本文中&#xff0c;您将学习如何创建和使用版本化的数据集作为可重现的机器学习流程的一部分。为了说明这一…

自定义MVC工作原理

目录 一、MVC二、MVC的演变2.1 极易MVCController层——Servletview层——JSP缺点&#xff1a;Servlet过多、代码冗余 2.2 简易MVCController层——Servletview层——JSP缺点&#xff1a;在Servlet中if语句冗余 2.3普易MVCController层——Servletview层——JSP缺点&#xff1a…

OBS播放NDI源

下载OBS Studio的NDI运行时和插件 https://github.com/obs-ndi/obs-ndi/releases 下载文章中的下面这两个文件,并直接双击安装。 或者从百度云下载也行: 链接:https://pan.baidu.com/s/1vNn1yMdCy6BZkKxKCq-kDw 提取码:cxxg 安装完成之后,打开OBS Studio 点击加号添…

RabbitMQ系列(11)--RabbitMQ交换机(Exchange)简介

1、交换机概念 生产者生产的消息从不会直接发送到队列&#xff0c;生产者只能把消息发送到交换机&#xff08;Exchange&#xff09;&#xff0c;交换机接收来着生产者的消息&#xff0c;另一方面把消息推入队列&#xff0c;交换机必须知道如何处理收到的消息&#xff0c;是应该…

【设计模式】第十五章:责任链模式详解及应用案例

系列文章 【设计模式】七大设计原则 【设计模式】第一章&#xff1a;单例模式 【设计模式】第二章&#xff1a;工厂模式 【设计模式】第三章&#xff1a;建造者模式 【设计模式】第四章&#xff1a;原型模式 【设计模式】第五章&#xff1a;适配器模式 【设计模式】第六章&…

银河麒麟服务器v10 sp1 nginx开机自动启动

接上一篇&#xff1a;银河麒麟服务器v10 sp1 安装 nginx_csdn_aspnet的博客-CSDN博客 设置开机自启动 定义服务启动文件内容&#xff1a; [Unit] Descriptionnginx - high performance web server Afternetwork.target remote-fs.target nss-lookup.target [Service] Ty…

menuconfig selected by 怎么处理

比方说我想取消掉flex&#xff0c;但是被强制生成了&#xff1a; 输入搜索命令查了一下&#xff1a; 搜一下selected by [y] 中的 linux_pam: 取消掉 这样就不用编flex了。

【HarmonyOS】元服务启动命令漫谈

在日常开发中&#xff0c;我们可以通过DevEco Studio&#xff0c;直接Run我们的元服务工程&#xff0c;在测试机上拉起我们开发的元服务页面。但是我们自己打包HarmonyOS元服务hap在手机上安装后是没有桌面图标的。虽然我们可以在设置的服务管理中找到我们安装的元服务&#xf…

Go语言操作MySql数据库

go-sql-driver/mysql库是Go语言官方推荐的MySQL驱动库&#xff0c;可以很方便地实现对MySQL数据库的连接和操作。本文记录以下使用go-sql-driver/mysql数据库驱动来操作mysql数据库。 目录 1.安装驱动程序 2.导入驱动包 3.操作数据库 3.1 获取mysql版本 3.2 创建表 3.3 …

详解JAVA Socket

目录 1.概述 2.使用 3.使用场景 3.1.web server中的网络通信 3.2.长连接 3.3.性能问题 1.概述 什么是网络通信&#xff1a; 就像打电话一样&#xff0c;两点间要通信&#xff0c;两点间就必须有连接&#xff0c;为了实现任意两个节点之间的通信&#xff0c;我们就必须采…

用户与组管理介绍

文章目录 一、服务器系统版本介绍二、用户管理1. 用户概述2. 内置账户3. 配置文件4. 用户管理命令 三、组管理1. 组概述2. 内置组&#xff08;系统自带的组&#xff09;3. 组管理命令 一、服务器系统版本介绍 Windows服务器系统&#xff1a;win2000、win2003、win2008、win2012…

Spring 与 Servlet-2

学习笔记&#xff08;加油呀&#xff09;&#xff1a; Spring的通知类型 Spring 通知类型按切面功能调用的不同时刻&#xff0c;可以分为提供了 5 种 Advice 类型 1、前置通知 Before advice&#xff1a;在某连接点之前执行的通知&#xff0c;但这个通知不能阻止连接点之前的…

SAP ABAP ALV FIELDCAT 字段设置详细说明

一、SAP ABAP ALV FIELDCAT 字段设置的位置&#xff1a; 二、SAP ABAP ALV FIELDCAT 字段设置的详细说明&#xff1a; 字段属性描述使用目的CFIELDNAME参照Currency单位的字段名根据单位显示相应值CHECKBOX设置成复选框字段输出选项COL POS字段的输出顺序字段输出选项COLDDICT…