代理模式(静态代理/动态代理)

代理模式(Proxy Pattern)

一 定义

为其他对象提供一种代理,以控制对这个对象的访问。
代理对象在客户端和目标对象之间起到了中介作用,起到保护或增强目标对象的作用。
属于结构型设计模式。

代理模式分为静态代理和动态代理。
静态代理是显式声明被代理对象,即硬编码出来的代理结构;
动态代理是动态配置和替换被代理对象,即通过在jvm中生成一个代理类来实现代理。

代理模式标准示例:

在这里插入图片描述
顶层会有 subject的接口,RealSubject 和 Proxy 都实现了 Subject接口。
Proxy中,拥有 RealSubject对象的引用,在Proxy的构造方法中,将RealSubject作为参数传入,然后在Proxy 的同名方法中,调用 RealSubject的方法。但是在调用 RealSubject的方法前后,可以加入Proxy的自有逻辑。

上述类图中各个类的代码如下:
subject 接口类:ISubject

public interface ISubject{void request();
}

被代理的类:RealSubject

public class RealSubject implements ISubject{public void request(){System.out.println("real reqeust");}
}

代理类:Proxy

public class Proxy implements ISubject{private ISubject target;public Proxy(ISubject target){this.target = target;}public void request(){before();//调用前逻辑target.request();after();//调用后逻辑}
}

客户端 ProxyClient

public class ProxyClient{public static void main(String[] args){Proxy proxy = new Proxy(new RealSubject());proxy.request();}
}

接下来,我们通过一个实际场景,来呈现出静态代理与动态代理的异同。


阿毛想租房,他首先考虑的是房产中介,因为房源集中在中介那里。

首先是静态代理的实现:

租户接口为:ITenant
中介类为:HouseProxy
实际租户有两个人:AmaoLaoSan
代码如下:

public interface ITenant {void require();
}
public class HouseProxy implements ITenant{private ITenant custom;public HouseProxy(ITenant custom){this.custom = custom;}public void require() {before();custom.require();after();}private void before() {System.out.println("当前代理权限通过验证,可以登录系统开始筛选房源。");}private void after() {System.out.println("按照上述要求找到的房源有:xxx");System.out.println();}
}
public class Amao implements ITenant {public void require() {System.out.println("阿毛的要求:一室一厅,2楼,朝南,2000元以内");}
}
public class LaoSan implements ITenant{public void require() {System.out.println("老三的要求:二室一厅,3楼以上,南北通透,4000元以内");}
}

客户端调用代码:

public class Client {public static void main(String[] args) {//中介为阿毛找房:HouseProxy proxy = new HouseProxy(new Amao());proxy.require();//中介为老三找房:HouseProxy proxy1 = new HouseProxy(new LaoSan());proxy1.require();}
}

执行结果为:

当前代理权限通过验证,可以登录系统开始筛选房源。
阿毛的要求:一室一厅,2楼,朝南,2000元以内
按照上述要求找到的房源有:xxx当前代理权限通过验证,可以登录系统开始筛选房源。
老三的要求:二室一厅,3楼以上,南北通透,4000元以内
按照上述要求找到的房源有:xxx

动态代理的实现

由于租户不是随时可以看房,所以要和中介约好看房时间,所以我们在ITenant 接口中,增加了看房时间。

public interface ITenant {void require();void lookHouseTime();
}

相应的,Amao和LaoSan 都需要实现这个方法:

public class Amao implements ITenant {public void require() {System.out.println("阿毛的要求:一室一厅,2楼,朝南,2000元以内");}public void lookHouseTime() {System.out.println("阿毛看房时间:周末");}
}
public class LaoSan implements ITenant {public void require() {System.out.println("老三的要求:二室一厅,3楼以上,南北通透,4000元以内");}public void lookHouseTime() {System.out.println("老三看房时间:周中");}
}

最后,是采用JDK动态代理实现的HouseProxy:

public class JDKHouseProxy implements InvocationHandler {private ITenant custom;public ITenant getInstance(ITenant custom){this.custom = custom;Class<?> clazz = custom.getClass();return (ITenant) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (!method.getName().equals("lookHouseTime")) {before();}Object result = method.invoke(this.custom,args);if (!method.getName().equals("lookHouseTime")) {after();}return result;}private void before() {System.out.println("--------------------");System.out.println("中介:当前代理权限通过验证,可以登录系统开始筛选房源。");}private void after() {System.out.println("中介:按照上述要求找到的房源有:xxx");}}

这里我们会发现,使用动态代理后,代理中介无需实现ITenant接口,如果ITenant接口发生变化,也不会对代理对象产生影响。
客户端调用类:

public class Client {public static void main(String[] args) {//中介为阿毛找房:JDKHouseProxy proxy = new JDKHouseProxy();ITenant tenantAmao = proxy.getInstance(new Amao());tenantAmao.require();tenantAmao.lookHouseTime();//中介为老三找房:JDKHouseProxy proxy1 = new JDKHouseProxy();ITenant laosan = proxy1.getInstance(new LaoSan());laosan.require();laosan.lookHouseTime();}
}

执行结果:

--------------------
中介:当前代理权限通过验证,可以登录系统开始筛选房源。
阿毛的要求:一室一厅,2楼,朝南,2000元以内
中介:按照上述要求找到的房源有:xxx
阿毛看房时间:周末
--------------------
中介:当前代理权限通过验证,可以登录系统开始筛选房源。
老三的要求:二室一厅,3楼以上,南北通透,4000元以内
中介:按照上述要求找到的房源有:xxx
老三看房时间:周中

动态代理除了JDK的API之外,还有cglib的方式。
二者区别在于,JDK的动态代理需要目标对象有继承体系(即实现接口);而cglib则不需要被代理对象存在继承体系。
以下是cglib的示例:
cglib的中介代理类:CglibHouseProxy

public class CglibHouseProxy implements MethodInterceptor {public Object getInstance(Class<?> clazz){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {if (!method.getName().equals("lookHouseTime")) {before();}Object result  = proxy.invokeSuper(obj,args);if (!method.getName().equals("lookHouseTime")) {after();}return result;}private void before() {System.out.println("--------------------");System.out.println("中介:当前代理权限通过验证,可以登录系统开始筛选房源。");}private void after() {System.out.println("中介:按照上述要求找到的房源有:xxx");}
}

客户端调用类:

public class CglibClient {public static void main(String[] args) {CglibHouseProxy proxy = new CglibHouseProxy();ITenant tenant = (ITenant) proxy.getInstance(Amao.class);tenant.require();tenant.lookHouseTime();}
}

执行结果:

--------------------
中介:当前代理权限通过验证,可以登录系统开始筛选房源。
阿毛的要求:一室一厅,2楼,朝南,2000元以内
中介:按照上述要求找到的房源有:xxx
阿毛看房时间:周末

补充:cglib pom.xml的引入

    <dependency><groupId>cglib</groupId><artifactId>cglib-nodep</artifactId><version>2.2</version></dependency>

以上就是本文全部内容。感谢您的阅读。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Mysql] 的基础知识和sql 语句.教你速成(上)——逻辑清晰,涵盖完整

目录 前言 上篇的内容概况 下篇的内容概况 数据库的分类 关系型数据库 常见的关系型数据库系统 非关系型数据库 1. 键值对数据库&#xff08;Key-Value Stores&#xff09; 特点&#xff1a; 常见的键值对数据库&#xff1a; 2. 文档数据库&#xff08;Document Store…

好用的linux一键换源脚本

最近发现一个好用的linux一键换源脚本&#xff0c;记录一下 官方链接 大陆使用 bash <(curl -sSL https://linuxmirrors.cn/main.sh)# github地址 bash <(curl -sSL https://raw.githubusercontent.com/SuperManito/LinuxMirrors/main/ChangeMirrors.sh) # gitee地址 …

Redis 网络模型

一、用户空间和内核空间 1.1 linux 简介 服务器大多采用 Linux 系统&#xff0c;这里我们以 Linux 为例来讲解&#xff0c;下面有两个不同的 linux 发行版&#xff0c;分别位 ubuntu 和 centos&#xff0c;其实发行版就是在 Linux 系统上包了一层壳。 任何 Linux 发行版&#…

RS-232协议详解:深入理解与实际应用

RS-232协议详解 RS-232协议&#xff0c;也称为推荐标准232&#xff0c;是一种用于串行通信的标准协议。它在计算机和外围设备之间的通信中广泛应用。本文将详细介绍RS-232协议的各个方面&#xff0c;包括其历史、工作原理、信号类型、连接方式、应用场景等。希望通过这篇文章&a…

如何使用React的lazy和Suspense来实现代码分割?

在React中&#xff0c;使用React.lazy和Suspense可以方便地实现组件的代码分割。代码分割是一种优化技术&#xff0c;它将代码拆分成多个包&#xff0c;然后按需加载这些包&#xff0c;从而加快应用的初始加载时间。下面是如何使用这两个API的基本步骤&#xff1a; 使用React.l…

软考初级网络管理员__网络单选题

1.某人的电子邮箱为 Rjspks163.com,对于Rjspks和163.com的正确理解为(2)&#xff0c;在发送电子邮件时&#xff0c;常用关键词使用中&#xff0c;(3)是错误的&#xff0c;采用的协议是(4)。若电子邮件出现字符乱码现象&#xff0c;以下方法中(5)一定不能解决该问题。 SNMP SM…

【安防天下】模拟视频监控系统——模拟监控系统的构成视频采集设备

文章目录 1 模拟监控系统的构成2 视频采集设备2.1 摄像机相关技术2.1.1 摄像机的工作原理2.1.2 摄像机的分类2.1.3 摄像机的主要参数 2.2 镜头相关介绍2.2.1 镜头的主要分类2.2.2 镜头的主要参数 1 模拟监控系统的构成 模拟视频监控系统又称闭路电视监控系统&#xff0c; 一般…

DB9母头接口定义485

在通信技术中&#xff0c;DB9接口广泛应用于串行通信&#xff0c;尤其是在RS232和RS485标准中。虽然DB9接口最常见于RS232通信&#xff0c;但通过适当的引脚映射&#xff0c;它也可以用于RS485通信。本文将详细介绍如何定义和使用DB9母头接口进行RS485连接。 DB9母头接口简介 …

这些帮助你成长的IOS应用,建议收藏

TrackIt TrackIt是一款功能丰富的任务清单、日程管理和习惯打卡应用&#xff0c;旨在帮助用户提高效率和专注力。通过这些功能&#xff0c;用户可以更好地规划时间和任务&#xff0c;从而实现个人目标和养成良好习惯。 在目标设定方面&#xff0c;SMART原则是一个常用的方法&a…

数据可视化实验五:seaborn绘制进阶图形

目录 一、绘制动态轨迹图 1.1 代码实现 1.2 绘制结果 二、使用seaborn绘制关系图 2.1 绘制散点图分析产品开发部已离职的员工的评分与平均工作时间 2.1.1 代码实现 2.1.2 绘制结果 ​编辑 2.2 基于波士顿房价数据&#xff0c;绘制房间数和房屋价格的折线图 2.2.1 代码…

redis 缓存jwt令牌设置更新时间 BUG修复

大家好&#xff0c;今天我又又又来了&#xff0c;hhhhh。 上文中 我们永redis缓存了token 但是我们发现了 一个bug &#xff0c;redis中缓存的token 是单用户才能实现的。 就是 我 redis中存储的键 名 为token 值 是jwt令牌 &#xff0c;但是如果 用户a 登录 之后 创建一个…

区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测

区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测 目录 区间预测 | Matlab实现EVO-CNN-SVM能量谷算法优化卷积神经网络支持向量机结合核密度估计多置信区间多变量回归区间预测效果一览基本介绍程序设计参考资…

【Ubuntu通用压力测试】Ubuntu16.04 CPU压力测试

使用 stress 对CPU进行压力测试 我也是一个ubuntu初学者&#xff0c;分享是Linux的优良美德。写的不好请大佬不要喷&#xff0c;多谢支持。 sudo apt-get update 日常先更新再安装东西不容易出错 sudo apt-get upgrade -y 继续升级一波 sudo apt-get install -y linux-tools…

【尚庭公寓SpringBoot + Vue 项目实战】移动端登录管理(二十)

【尚庭公寓SpringBoot Vue 项目实战】移动端登录管理&#xff08;二十&#xff09; 文章目录 【尚庭公寓SpringBoot Vue 项目实战】移动端登录管理&#xff08;二十&#xff09;1、登录业务2、接口开发2.1、获取短信验证码2.2、登录和注册接口2.3、查询登录用户的个人信息 1、…

后端学习笔记:Python基础

后端学习笔记&#xff1a;Python基础 数据类型&#xff1a; Python中主要有以下几种常用的基本数据类型&#xff1a; String 字符串类型&#xff0c;用单引号或者双引号引用Number 数字类型&#xff0c;包括浮点数&#xff0c;整数&#xff0c;长整数和复数List 列表项&…

ENVI实战—一文搞定非监督分类

实验1&#xff1a;使用isodata法分类 目的&#xff1a;学会使用isodata法开展非监督分类 过程&#xff1a; ①导入影像&#xff1a;打开ENVI&#xff0c;按照“文件→打开为→光学传感器→ESA→Sentinel-2”的顺序&#xff0c;打开实验1下载的哨兵2号数据。 图1 ②区域裁剪…

Hbase搭建教程

Hbase搭建教程 期待您的关注 ☀小白的Hbase学习笔记 目录 Hbase搭建教程 1.上传hbase的jar包并解压 2.重新登录 3.启动zookeeper 4.配置环境变量 5.关闭ZK的默认配置 6.修改hbase-site.xml文件 7.修改regionservers文件 8.将配置好的文件分发给其它节点 9.配置环境变量…

PyCharm新手入门

前言 在之前《Python集成开发工具的选择》一文中介绍了python初学者可以使用Jupyter Notebook&#xff0c;Jupyter Notebook简单易用&#xff0c;可以用来练习代码编写&#xff0c;但是实际生产开发环境使用这个工具是远远不够用的&#xff0c;因为实际软件开发中需要软件调试…

LabVIEW程序闪退问题

LabVIEW程序出现闪退问题可能源于多个方面&#xff0c;包括软件兼容性、内存管理、代码质量、硬件兼容性和环境因素。本文将从这些角度进行详细分析&#xff0c;探讨可能的原因和解决方案&#xff0c;并提供预防措施&#xff0c;以帮助用户避免和解决LabVIEW程序闪退的问题。 1…

软考高级论文真题“论大数据lambda架构”

论文真题 大数据处理架构是专门用于处理和分析巨量复杂数据集的软件架构。它通常包括数据收集、存储、处理、分析和可视化等多个层面&#xff0c;旨在从海量、多样化的数据中提取有价值的信息。Lambda架构是大数据平台里最成熟、最稳定的架构&#xff0c;它是一种将批处理和流…