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

news2024/10/25 0:24:32

代理模式(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.coloradmin.cn/o/1842679.html

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

相关文章

华为Pocket 2,夏日达人的时尚新宠!

夏天炎炎&#xff0c;适合撒欢~但时尚与便利从不缺席&#xff01;我的时尚新宠华为Pocket 2跟我一起。 高颜值的外观一定是出行拍照和搭配单品的选项&#xff0c;这款小巧精致的手机&#xff0c;外屏设计超级时尚,轻松搭配出夏日潮流风。它的外屏还支持个性化设置&#xff0c;…

OpenVINO™ 2024.2 发布--推出LLM专属API !服务持续增强,提升AI生成新境界

点击蓝字 关注我们,让开发变得更有趣 作者 | 武卓 博士 排版 | 李擎 Hello&#xff0c; OpenVINO™ 2024.2 对我们来说&#xff0c;这是非常忙碌的几周&#xff0c;因为我们正在努力根据您的反馈改进我们的产品特性&#xff0c;并扩展生态系统以涵盖其它场景和用例。 让我们看看…

【Python】使用matplotlib绘制图形(曲线图、条形图、饼图等)

文章目录 一、什么是matplotlib二、matplotlib 支持的图形三、如何使用matplotlib1. 安装matplotlib2. 导入matplotlib.pyplot3. 准备数据4. 绘制图形5. 定制图形6. 显示或保存图形7. &#xff08;可选&#xff09;使用subplots创建多个子图注意事项&#xff1a; 四、常见图形使…

软考高级论文真题“论湖仓一体架构及其应用”

论文真题 随着5G、大数据、人工智能、物联网等技术的不断成熟&#xff0c;各行各业的业务场景日益复杂&#xff0c;企业数据呈现出大规模、多样性的特点&#xff0c;特别是非结构化数据呈现出爆发式增长趋势。在这一背景下&#xff0c;企业数据管理不再局限于传统的结构化OLTP…

算法008:四数之合

四数之和. - 备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能,轻松拿下世界 IT 名企 Dream Offer。https://leetcode.cn/problems/4sum/description/ 在前面的两个题中&#xff0c;我们已经完成了两数之和和三数之和&#xff0c;到本题四…

【linux】奇怪?linux搭建离线仓库为什么执行yum grouplist没有信息呐?

奇怪&#xff1f;linux搭建离线仓库为什么执行yum grouplist没有信息呐&#xff1f; 正常现象如下&#xff1a; 怎么样才能解决这个问题&#xff1f; 1、在同系统、同正常环境下查找一下groups.xml find / -name "*groups*.xml"可以看到下面有很多groups.xml 2、在…

Transformer 模型的 PyTorch 实现

Google 2017年的论文 Attention is all you need 阐释了什么叫做大道至简&#xff01;该论文提出了Transformer模型&#xff0c;完全基于Attention mechanism&#xff0c;抛弃了传统的RNN和CNN。 我们根据论文的结构图&#xff0c;一步一步使用 PyTorch实现这个Transformer模型…

智慧乡村和美人家信息化系统

一、简介 智慧乡村和美人家信息化系统是一个综合管理平台&#xff0c;集成了首页概览、一张图可视化、数据填报、智能评估、便捷申报、公开公示、任务管理、活动发布和灵活配置等功能。该系统不仅提升了乡村管理效率&#xff0c;也优化了家庭生活的便捷性。通过一张图&#xf…

搭建群辉AudioStation音乐库

目录 1、安装套件 2、配置歌词插件 3、配置音乐库 4、PC端使用 5、手机APP (1)DS Audio (2)音流 6、关于歌曲信息及封面 (1)歌词 (2)封面 作为音乐爱好者,在NAS上存了大量的无损音乐,用文件流量的方式播放,体验未免欠佳。这次我们打造自己的音乐库,随时随…

360vr党建线上主题展立体化呈现企业的文化理念和品牌形象

在现代科技的引领下&#xff0c;艺术与VR虚拟现实技术相融合必将成为趋势&#xff0c;深圳VR公司华锐视点荣幸地推出VR艺术品虚拟展厅&#xff0c;为您带来前所未有的艺术观赏体验。体验者足不出户即可置身于一个充满创意与灵感的虚拟艺术空间。 我们深入了解每一位客户的需求与…

数据库7大约束

4 约束 数据类型 什么是数据&#xff1a;数字、小说、图片、音乐、视频 针对不同的数据展现形式&#xff0c;我们对数据进行了分类&#xff0c;数据类型。 数字类型&#xff1a;存放数字的&#xff0c;int浮点型类型&#xff1a;存放数字&#xff0c;float&#xff0c;小数字…

大数据关联规则算法

关联性&#xff08;Association&#xff09; 定义&#xff1a;指一个变量能够提供有关另一个变量的信息。特点&#xff1a;关联性是一个广泛的概念&#xff0c;它可以包括直接的、间接的、强的或弱的联系。 相关性&#xff08;Correlation&#xff09; 定义&#xff1a;指两个…

低版本火狐浏览器报错:class is a reserved identifier

低版本火狐浏览器报错&#xff1a;class is a reserved identifier 原因&#xff1a;react-dnd&#xff0c;dnd-core 等node包的相关依赖有过更新&#xff0c;使得在低版本火狐浏览器中不支持 class 解决方法&#xff1a;在使用webpack打包构建时&#xff0c;编译排除node_modu…

SonarQube集成Jenkins平台搭建

SonarQube平台搭建 一、项目搭建的必要条件 SonarQube 8.9.10 previous LTS 依据公司现有服务目前的Jdk版本1.8&#xff0c;需要选择一个适用的长期支持版本&#xff0c;我在这里选用的是SonarQube 8.9.10 previous LTS。下载地址&#xff1a;Download Previous SonarQube Ver…

2000-2022年全国平均气温数据,多年份,多字段可查询,可预览数据

基本信息. 数据名称: 全国平均气温数据 数据格式: Shp、Excel 数据时间: 2000-2022年 数据几何类型: 面 数据坐标系: WGS84坐标系 数据来源&#xff1a;网络公开数据 数据字段&#xff1a; 序号字段名称字段说明1xzqhdm行政区划代码2xzqhmc行政区划名称3qw2001m01…

E36150系列 自动量程台式电源

E36150系列 自动量程台式电源 <<<KEYSIGHT是德科技>>> “ Keysight E36150 系列自动量程台式直流电源包含两个型号&#xff0c;其单通道输出功率可达 800 W。 E36150 系列可输出高达 60 V 的电压和 80 A 的电流&#xff0c;其可用功率足以满足您的测试需…

MySQL之优化服务器设置(四)

优化服务器设置 InnoDB的IO配置 双写缓冲(Doublewrite Buffer) InnoDB用双写缓冲来避免页没写完整所导致的数据损坏。当一个磁盘写操作不能完整地完成时&#xff0c;不完整的页写入就可能发生&#xff0c;16KB的页可能只有一部分被写到磁盘上。有多种多样的原因(崩溃、Bug&am…

阿里云PAI大模型评测最佳实践

作者&#xff1a;施晨、之用、南茵、求伯、一耘、临在 背景信息 内容简介 在大模型时代&#xff0c;随着模型效果的显著提升&#xff0c;模型评测的重要性日益凸显。科学、高效的模型评测&#xff0c;不仅能帮助开发者有效地衡量和对比不同模型的性能&#xff0c;更能指导他…

OS复习笔记ch11-3

接下来&#xff0c;我们简单地回顾一下I/O缓冲&#xff08;之前在ch5-4-1的时候有提到过&#xff09; I/O缓冲 背景&#xff1a; 假设进程I/O需要在灰色区间读写&#xff0c;而灰色区间由于阻塞而被对换出去了&#xff0c;此时OS找不到对应的内存地址&#xff0c;这样就容易发…

Shell脚本、相关命令;重定向、管道符、变量相关命令讲解

目录 Shell脚本 概念 执行命令流程的交互区别 交互式 非交互式 Shell脚本应用场景 Shell的作用 Shell的作用 —— 命令解释器&#xff0c;“翻译官” 列出系统中全部解释器 实验 脚本的基本书写格式和执行命令 在子bash下执行脚本 指定解释器的方式执行脚本 指定…