23模式--代理模式

news2025/2/22 13:35:14

本篇主要聊一些23中模型中的代理模式:

看一下百度百科的解释:

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式其实有点像是:合作方—经纪人—明星这样关系。

合作方如果想要找明星合作,首先要找到经纪人,具体的谈判合同的事情,先和经纪人进行协商,最后达成合作。

其实代理模式有很多不同的形式,主要有三种:静态代理,动态代理(JDK代理,接口代理),Cglib代理。

一般的组成有:

  • 抽象角色:通过接口或抽象类生命真实角色实现的业务方法。
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

静态代理

静态代理在使用时,需要定义接口或者抽象类,也就是被代理对象(明星)与代理对象(经纪人)需要实现相同的接口或者是继承相同的父类。

现在进行代码演示:

  • 接口

    public interface BusinessInfa {
    //    签约方法
       void signContract();
    
    }
    
    
  • 被代理类

    public class Star implements BusinessInfa {
        @Override
        public void signContract() {
            System.out.println("我是大明星,我同意这份合同了");
        }
    }
    
    
  • 代理人

    public class Agent implements BusinessInfa{
    //    代理谁
        Star  star;
    
        public Agent(Star star) {
            this.star = star;
        }
    
        @Override
        public void signContract() {
    //        先联系明星经纪人
            System.out.println("你好,你找我家明星合作,可以和我谈");
    //        谈合同不是简单就可以签约的,肯定要涉及道各种拉扯,合同条款以及费用
            System.out.println("和经纪人一起疯狂的如果老太太菜市场砍价一般,深入几天各种约各种谈");
    //        最后同意了合同
            this.star.signContract();
    //        就算合约签了,具体后面合作中的事情
            System.out.println("具体合作后现场一些细节,比如我家大明星,剧本改下台词超过十个字了,记不住台词");
    
        }
    }
    
    
  • 客户端调用代理人

    public class client {
        public static void main(String[] args) {
            //    需要找大明星的联系方式没有,去找大明星公开的经纪人联系
            System.out.println("我是合作方,需要联系大明星,没办法只能先联系经纪人");
            BusinessInfa businessInfa=new Agent(new Star());
            businessInfa.signContract();
        }
    
    
    }
    
    

然后看一下结果:

在这里插入图片描述

现在看一下静态代理的优缺点

  • 优点: 在不修改目标的对象功能的前提下,通过代理对象对目标公共进行扩展,例子中不会对明星签约的行动进行修改,但是具体谈判细节,以及合作后的出现事故等投通过经纪人进行谈判,毕竟明星给了经纪人钱的。
  • 缺点:代理对象需要与目标的对象实现一样的接口,所以会有很多代理类,一旦接口增量了方法,目标对象和代理对象都要维护。也就是比如合作定义的行为,如果增加了明星和经纪人都需要增加行为。

静态代理其实是最方便理解代理这个原理的,而其它无论如何变化,都不能离开这个原理。

动态代理:jdk代理

动态代理类,是位于Java.lang.reflect包下类别的Interface InvocationHandler。其实也是通过反射实现的,所以代理对象不需要实现接口,但是目标对象要实现接口,否则不能用动态代理。而这是利用JDK的API实现的动态代理是在内存中构建代理对象的。

动态代理也被称之为JDK代理,接口代理。

还是老规矩直接用代码演示:

  • 被代理类接口

    //商务接口  毕竟经纪人代理明星的业务,也是要统一一下什么业务能代理
    public interface BusinessInfa {
    //    签约方法
       void signContract();
       void breakContract();
    
    }
    
    
  • 被代理类:

    public class Agent {
        //    代理谁
        Object target;
    
        public Agent(Object target) {
            this.target = target;
        }
    
    
    //     动态创建不同的代理对象
        public Object getProxyObject(){
            Object object=Proxy.newProxyInstance(this.target.getClass().getClassLoader(),
                    this.target.getClass().getInterfaces(),new myInvocationHandler());
    
            return object;
    
        }
       class myInvocationHandler implements InvocationHandler{
    
           @Override
    //        proxy 在其上调用方法的代理实例   method被代理的方法    代理方法中的参数args
           public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 对第一个参数好奇是什么
               System.out.println("=======================================");
    //           System.out.println(proxy); 这样打印会报错  不过可以看出第一个参数应该是代理对象 一般的时候没有什么用
               System.out.println(proxy.getClass());
               System.out.println("=======================================");
    
    //           因为要运行的方法没有返回值,所以不接受数据,通过return返回了 同时这里也是可以根据反射判断不同的方法,然后加入不同的逻辑
               if(method.getName()=="signContract" || method.getName().equals("signContract")){
                   System.out.println("你好,你找我家明星合作,可以和我谈");
                   method.invoke(target,args);
                   System.out.println("后期出现事情,你们必须改,因为我家明星最漂亮,哪怕是她的错你们会原谅的。");
                   //           这里可以返回所代理的类要运行的方法,不过因为我没有返回值,所以直接返回空
                   return null;
               }else if (method.getName()=="breakContract" || method.getName().equals("breakContract")){
                   System.out.println("你好,你们的错误");
                   method.invoke(target,args);
                   System.out.println("可恶的合作方,不理你们了");
                   //           这里可以返回所代理的类要运行的方法,不过因为我没有返回值,所以直接返回空
                   return null;
               }
    
               return null;
           }
       }
    }
    
  • 调用类

    public class client {
        public static void main(String[] args) {
            //    需要找大明星的联系方式没有,去找大明星公开的经纪人联系
            System.out.println("我是合作方,需要联系大明星,没办法只能先联系经纪人");
            Agent agent=  new Agent(new Star());
            BusinessInfa businessInfa = (BusinessInfa) agent.getProxyObject();
            businessInfa.signContract();
            System.out.println("*********************************************");
            businessInfa.breakContract();
        }
    }
    

    然后看一下输出结果:

在这里插入图片描述
可以看下类关系图:
在这里插入图片描述

jdk代理的优缺点:

  • 优点 :JDK原声动态代理时java原声支持的、不需要任何外部依赖。而且可以动态生成代理类,方不需要像静态代理哪里代理类因为接口变化而不停的调整。
  • 缺点:但是它只能基于接口进行代理,也就是被代理的对象也需要有一个接口,不然无法使用jdk代理,同时因为它已经继承了proxy了,java不支持多继承。

动态代理:Cglib代理

无论静态代理还是上面提到的JDK动态代理都需要实现一个接口,但是有时候对象只是一个单独的对象,并没有实现任何的接口,这个时候就需要使用目标对象的子类来实现。而聊到的Cglib动态代理就算通过这种方式实现代理的。

Cglib代理也叫做子类代理,其是再内存中构建了一个子类对象,从而实现对目标对象功能的扩展。Cglib代理是可以再运行期扩展java类与实现java接口,所以其广泛被需要AOP框架使用,其中就包括spring,通过Cglib实现方法拦截。

因为是内存中动态构建子类,所以Cglib代理类不能为final。同样如果目标对象的方法如果为final或者static,代理也会不对其方法进行代理。

其实AOP中不一定会都选择使用Cglib代理,我们开发中同样是如此选择的:

  • 目标对象需要实现接口,那就使用JDK代理。
  • 目标对象不需要实现接口,那句使用Cglib代理。

Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类。

需要Jar包

这个有两种情况,

  • 如果引入的是Cglib的jar包就需要四个包:

    asm.jar asm-commons.jar asm-tree.jar Cglib-*.*.jar(自己选版本)

  • 如果使用 cglib-nodep的jar,直接导入这一个就行,因为其打包了cglib所需要的依赖jar包

代码演示

  • 被代理的对象,无需实现接口

    public class Star  {
    
        public void signContract() {
            System.out.println("我是大明星,我同意这份合同了");
        }
    
    
        public void breakContract() {
            System.out.println("台词超过三句了,编辑不修改剧本,合作方的错误,毁约了。。。。");
        }
    }
    
    
  • 使用Cglib代理的增强代理类

    // 经纪人代理  需要实现Cglib代理中接口方法MethodInterceptor
    public class Agent implements MethodInterceptor {
        //    代理谁
        Object target;
    
        public Agent(Object target) {
            this.target = target;
        }
    
    
    //     动态创建不同的代理对象
        public Object getProxyObject(){
    //        创建一个Cglib包下的工具栏
            Enhancer enhancer=new Enhancer();
    //        设置父类
            enhancer.setSuperclass(target.getClass());
    //        设置回调函数,这个回调本身是自己所以
            enhancer.setCallback((Callback) this);
    // 创建子类对象 也就是代理对象
            return enhancer.create();
    
        }
    
        @Override
    //    需要重写这个方法,代理类调用方法的时候会走个方法
    //     o 代表的this 就算代理增强的对象  Method 被代理对象执行的方法,也就是拦截的方法   objects 方法的参数   methodProxy 用于调用super(非拦截方法);可以根据需要调用多次
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            //           因为要运行的方法没有返回值,所以不接受数据,通过return返回了 同时这里也是可以根据反射判断不同的方法,然后加入不同的逻辑
            if(method.getName()=="signContract" || method.getName().equals("signContract")){
                System.out.println("你好,你找我家明星合作,可以和我谈");
                method.invoke(target,objects);
                System.out.println("后期出现事情,你们必须改,因为我家明星最漂亮,哪怕是她的错你们会原谅的。");
                //           这里可以返回所代理的类要运行的方法,不过因为我没有返回值,所以直接返回空
                return null;
            }else if (method.getName()=="breakContract" || method.getName().equals("breakContract")){
                System.out.println("你好,你们的错误");
                method.invoke(target,objects);
                System.out.println("可恶的合作方,不理你们了");
                //           这里可以返回所代理的类要运行的方法,不过因为我没有返回值,所以直接返回空
                return null;
            }
    
            return null;
        }
    }
    
  • 调用测试的类

    public class client {
        public static void main(String[] args) {
            //    需要找大明星的联系方式没有,去找大明星公开的经纪人联系
            System.out.println("我是合作方,需要联系大明星,没办法只能先联系经纪人");
            Agent agent=  new Agent(new Star());
            Star star = (Star) agent.getProxyObject();
            star.signContract();
            System.out.println("*********************************************");
            star.breakContract();
        }
    }
    
    

在这里插入图片描述

也没有问题,可以实现动态代理。

补充 其它代理

这个只是写了几个代理的名字,也不是全部。

  • 防火墙代理: 内网通过代理穿透防火墙,对公网进行访问。
  • 缓存代理: 如果获取网络资源有些从缓存中回去资源,如果没有了再从其它地方获取资源。
  • 远程代理:远程代理通过网络和真正的远程对象沟通信息。常见的翻墙梯子就算这个逻辑。
  • 同步代理: 主要使用在多线程编程中,完成多线程间同步工作

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

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

相关文章

Python连接MySQL实现增删改查详细教程

文章目录前言一、环境准备二、操作步骤1.安装Python依赖库2.创建测试数据表3. 编写操作数据库核心类4. 测试数据添加5. 测试数据删除6. 测试数据更新7. 测试数据查询三、完整代码总结前言 Python语言经过了很多年的发展,生态非常丰富,热度只增不减&…

微搭问搭001-如何清空表单的数据

韩老师,我点关闭按钮后,弹窗从新打开,里面的数据还在,这个可以从新打开清除不? 点关闭的时候清掉 就是清楚不掉也?咋清掉 清掉表单内容有属性可以做到? $page.widgets.id**.value “” 就可以实…

HCIP-5.4OSPF路由聚合、缺省路由

1、路由聚合 OSPF 是一种链路状态路由协议,因此 OSPF路由器不传输路由,而是传输链路状态信息。因此,OSPF 路由通过汇总 LSA 来控制链路状态信息的传输,从而减小 LSDB 数据库的大小,进而控制路由的汇总。 由于OSPF路由…

Object对象键值的输出循序到底如何排列的?

1.日常摸鱼看八股 今天又是复习八股文的一天,发现还是彻底懂得原理才好和面试官吹牛批呀。 接着来看看我chat大宝贝的回答: 在现代浏览器中,Object 对象的键值输出循序是比较稳定的,通常是按照如下顺序输出: 所有的数…

打怪升级之如何发送HEX进制的数据出去

Hex数据老大难 不少人都困扰于如何将电脑中读取到的string类型的数据变成整形发送出去。一半来说,不论你调用的通信方式是串口的还是网络的,亦或是PCIE的,其在电脑端的实际情况都是以系统API的形式呈现的。而系统API函数提供的接口&#xff…

项目实战典型案例23——-注册上nacos上的部分服务总是出现频繁掉线的情况

注册上nacos上的部分服务总是出现频繁掉线的情况一:背景介绍二:思路&方案解决问题过程涉及到的知识nacos服务注册和服务发现一:背景介绍 spring cloud项目通过nacos作为服务中心和配置中心,出现的问题是其中几个服务总是出现…

【电子通识】案例:从YS-CH341T USB转IIC和UART模块使用学习如何找资料

最近在调一个充电芯片,要用到IIC与充电芯片通信来读取和写入充电芯片寄存器,控制充电芯片的各种参数。从以前老员工那里捡到一个这样的模块,模块背面写了YS-CH341T。看着有IIC通信的样子,所以先在网上找一下资料。首先先在网上找到…

npm安装依赖包:405 Method Not Allowed...

运用npm安装依赖包时报错,错误如下。 解决思路: 关注到错误信息上写明了 Method Not Allowed,其后注明了 GET请求以及一个url,说明极有可能是不允许向这个路由发送GET请求; 在浏览器中尝试打开这个地址,结…

在分析了共50亿美元的加密融资之后,我们发现了这些

对加密市场嗅觉敏锐的玩家来说,市场中项目融资是不得不关注的选项,不少优质项目拿到了巨额融资之后,被大家所关注,在20-21年期间,行业内也出现了不少一级机构,布局早期项目,获取时代红利已经成为…

圆桌(满足客人空座需求,合理安排客人入座圆桌,准备最少的椅子)

CSDN周赛第30期第四题算法解析。 (本文获得CSDN质量评分【91】)【学习的细节是欢悦的历程】Python 官网:https://www.python.org/ Free:大咖免费“圣经”教程《 python 完全自学教程》,不仅仅是基础那么简单…… 地址:https://lq…

什么是业务运营?关键组成部分有哪些?

企业领导者使用收入运营和智能软件等技术来分析买家的不同接触点。这些见解决定了客户互动的成败,从而改善了业务运营,从而带来了成功。 什么是业务运营? 业务运营包括企业为保持盈利而执行的一系列日常任务。虽然这些任务可能因业务类型或行…

主辅助服务市场出清模型研究【旋转备用】(Matlab代码实现)

👨‍🎓个人主页:研学社的博客💥💥💞💞欢迎来到本博客❤️❤️💥💥🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密…

【已解决】Python的坑:os.system()运行带有空格的长路径和双引号参数有bug

在Python代码里运行DOS命令,可以使用os库的os.system()函数。其用法很简单,需要注意的是os.system不会返回输出的结果赋予一个变量。今天我发现了一个bug:当DOS命令行带有双引号路径、双引号参数时,os.system()运行的结果总是显示…

带你认识什么是485通信

在现代工业控制系统中,常常需要实现分布式控制,而分布式控制需要实现不同设备之间的通信。其中,485通信协议是一种被广泛使用的通信协议之一。1. 介绍A. 485通信的定义485通信协议是一种串行通信协议,也被称为RS-485。它是由美国电…

300. 最长递增子序列——【Leetcode每日刷题】

300. 最长递增子序列 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子…

leetcode 1648. 销售价值减少的颜色球

1648. 销售价值减少的颜色球这道题不知为何总想记录下来,思路很简单,但是实现总是出错,这也许就是要记录的原因。再一个觉得题解写的比较难以理解,所以再细致一些解析。希望可以帮到实在搞不懂的同学 思路: 目的:我们…

聚观早报|谷歌发布最大视觉语言模型;王兴投资王慧文ChatGPT项目

今日要闻:谷歌发布全球最大视觉语言模型;马斯克预计Twitter下季度现金流转正;王兴投资王慧文ChatGPT项目;美国拟明年 11 月开展载人绕月飞行;慧与科技宣布收购Athonet谷歌发布全球最大视觉语言模型 近日,来…

RocketMQ重复消费的症状以及解决方案

RocketMQ重复消费的症状以及解决方案 生产消息时重复 症状 当一条消息已被成功发送到 消费者 并完成持久化,此时出现了网络闪断或者客户端宕机,导致服务端对客户端应答失败。 如果此时 生产者 意识到消息发送失败并尝试再次发送消息,消费者…

学习 Python 之 Pygame 开发魂斗罗(十一)

学习 Python 之 Pygame 开发魂斗罗(十一)继续编写魂斗罗1. 改写主类函数中的代码顺序2. 修改玩家初始化3. 显示玩家生命值4. 设置玩家碰到敌人死亡5. 设置敌人子弹击中玩家6. 修改updatePlayerPosition()函数逻辑继续编写魂斗罗 在上次的博客学习 Pytho…

【Flutter从入门到入坑】Flutter 知识体系

学习 Flutter 需要掌握哪些知识? 终端设备越来越碎片化,需要支持的操作系统越来越多,从研发效率和维护成本综合考虑,跨平台开发一定是未来大前端的趋势,我们应该拥抱变化。而 Flutter 提供了一套彻底的移动跨平台方案…