设计模式之代理模式(静态代理动态代理)

news2025/2/25 6:18:00

目录

1、什么是代理模式

2、代理模式的结构

3、代理模式的实现

3.1 静态代理和动态代理概念

3.2 静态代理

3.3 动态搭理

3.3.1 代码实现

3.3.2 Proxy类讲解

4、动态代理VS静态代理

5、代理模式优缺点


1、什么是代理模式

由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

2、代理模式的结构

代理(Proxy)模式分为三种角色:

  • 抽象主题(Subject)类: 通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类: 实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类 : 提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

3、代理模式的实现

3.1 静态代理和动态代理概念

Java中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态代理代理类则是在Java运行时动态生成。动态代理又有JDK代理和CGLib代理两种。

(本文中的动态代理主要讲解的是JDK代理,如果大家对CGLib代理感兴趣的话可以自行查阅网上的文章) 

3.2 静态代理

我们直接通过案例来感受一下动态代理,以下是场景描述:

一般明星(对象本身)都会有一个经纪人(代理对象)来帮他处理一些事情,比如明星开演唱会之前收门票费用,预约场地,演唱会结束之后调查观众对该演唱会的反馈之类的事情肯定不能交给大明星做吧,所以这些事情一般都是交给经纪人去处理。

这个例子就是一个典型的代理例子,因此我们来看看通过静态代理如何实现:

明星类(抽象主题类):

public interface bigStar {//抽象主题类
    String Sing();
    void Dance();
}

坤坤类(真实主题类):

public class KunKun implements bigStar{ //真实主题类
    public String Sing(){
        System.out.println("大明星:坤坤开始唱歌");
        return "鸡你太美"; //返回歌词
    }
    public void Dance(){
        System.out.println("大明星:坤坤开始跳舞");
    }
}

 经纪人类(代理类):

public class StaticProxy implements bigStar{ //代理类
    private bigStar star;
    public StaticProxy(bigStar bigStar){
        star=bigStar;
    }

    @Override
    public String Sing() {
        System.out.println("唱歌前收取门票费用、预约场地");
        String sing = star.Sing();
        System.out.println("唱歌结束后帮忙调查观众反馈");
        return sing;
    }

    @Override
    public void Dance() {
        System.out.println("跳舞前收取门票费用、预约场地");
        star.Dance();
        System.out.println("跳舞结束后帮忙调查观众反馈");
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        KunKun kunKun = new KunKun();
        StaticProxy proxy = new StaticProxy(kunKun);
        proxy.Dance();
        System.out.println("------");
        String sing = proxy.Sing();
        System.out.println("歌词为:"+sing);
    }
}

运行结果如下:

可见,我们通过“静态代理”的方式实现了“代理模式”,成功在“坤坤”唱歌、跳舞前做好了准备工作以及在结束后做好了调查观众反馈的工作。这些都是代理类来完成的,看到这里大家肯定意识到了代理模式的一个好处就是:“在被代理对象方法执行前后能做一定的处理、加强”。

但是上述静态代理模式有没有缺点呢?

有!而且很明显!那就是:“杂!乱!如果接口增加一个方法,静态代理模式除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。”

因此,我们引出另一种实现代理模式的方法:“动态代理”。

3.3 动态搭理

3.3.1 代码实现

动态代理的JDK代理实现主要是通过“Proxy类”来实现的,我们直接来看代码实现,大家耐心看,代码里面有很详细的注释。看不懂可以先看底下对于里面参数的讲解部分。

大明星类(抽象主题类):

public interface bigStar { //大明星类(抽象主题类)
    public String Sing();
    public void Dance();
}

坤坤类(真实主题类):

public class KUN implements bigStar { //坤坤类(真实主题类)
    @Override
    public String Sing() {
        System.out.println("坤坤在唱歌......");
        //返回歌词
        return "鸡你太美";
    }

    @Override
    public void Dance() {
        System.out.println("坤坤在跳舞");
    }
}

经纪人(代理类):

public class StarProxyFactory { //经纪人(代理类)
    public static bigStar getProxy(bigStar star){
        bigStar result=(bigStar)Proxy.newProxyInstance(   //newProxyInstance()方法即返回代理对象
//                newProxyInstance()方法参数说明:
//                ClassLoader loader : 类加载器,用于加载代理类,使用真实对象的类加载器即可
//                Class<?>[] interfaces : 真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口
//                InvocationHandler h : 代理对象的调用处理程序
                star.getClass().getClassLoader(),
                star.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
//                    InvocationHandler中invoke方法参数说明:
//                    proxy:代理对象
//                    method:对应于在代理对象上调用的接口方法的 Method 实例,比如我们调用了“Sing()”这个方法,那么对应的就是“Sing()”的Method实例
//                    args:对应我们方法传入的参数
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("场地布置、收取门票费用");
                        Object invoke = method.invoke(star, args);
                        System.out.println("场地打扫");
                        return invoke; //返回方法调用结果
                    }
                }
        );
        return result;
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        KUN kun = new KUN();
        bigStar proxy = StarProxyFactory.getProxy(kun);//获取动态代理对象
        //验证是否被代理
        proxy.Dance();
        System.out.println("--------------");
        String sing = proxy.Sing();
        System.out.println("歌词为:"+sing);
    }
}

运行结果如下:

可见,我们通过Java提供的“Proxy类”也实现了代理的效果,但是大家看完可能会一脸懵逼,发生了什么?我在哪?我是谁?

因此接下来我们对“Proxy类”这个类做一个详细的解释。

3.3.2 Proxy类讲解

首先,我们刚刚是通过Proxy.newProxyInstance()来获取一个代理对象,它所需要的参数如下:

可见,我们如果使用Proxy.newProxyInstance()的话,需要对它传入以下参数:

①参数一:指类加载器,意思是需要我们告诉它我们需要用哪个类加载器去加载代理对象,通常我们代理对象与被代理对象可以使用同一个类加载器,因此比如上文我们是代理star对象,因此我们传入的类加载器就是:“star.getClass().getClassLoader()”。

②参数二:指真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口,因此我们也直接传入真实对象的接口即可:“star.getClass().getInterfaces()”。

③参数三:指代理对象最终调用的程序,一般代理对象调用某个方法后,都会走我们参数三写的这个方法,大家往回看代码会发现我们参数三传入了一个匿名内部类对象“new InvocationHandler()”

大家又可以发现,这个“InvocationHandler类”创建对象时,要求重写里面的invoke方法:

 我们再来逐一说说这几个参数的作用:

  • proxy:代理对象本身
  • method:对应于在代理对象上调用的接口方法的 Method 实例,比如我们调用了“Sing()”这个方法,那么对应的就是“Sing()”的Method实例
  • args:对应我们方法传入的参数

因此呢,我们可以在invoke方法里面做一些方法加强(比如我们之前的代码),也就是我们的“代理”。

以上便是动态代理实现代理模式的代码。

4、动态代理VS静态代理

动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。
如果接口增加一个方法,静态代理模式除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。而动态代理不会出现该问题

5、代理模式优缺点

优点:

  •  代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用。
  • 代理对象可以扩展目标对象的功能。
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度。

缺点:

  • 增加了系统的复杂度。

以上是代理模式的详解,大家麻烦点个赞和关注可以嘛!现在点关注就是老粉啦!

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

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

相关文章

【开发工具】 Adobe 2022 最详细的安装方法 就是这么简单 绿色 安全方便

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

vulnhub靶场之Black-Widow-final

1.信息收集 探测存活主机&#xff0c;发现192.168.239.177存活 对目标主机192.168.239.177进行端口扫描&#xff0c;发现存活22、80、111、2049、3128等端口 在浏览器中访问http://192.168.239.177&#xff0c;并查看源码&#xff0c;未发现有用的信息 对http://192.168.23…

【openGauss实战11】性能报告WDR深度解读

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

c++题库练习

19. 以下叙述中正确的是&#xff08;&#xff09; A 使用typedef说明新类型名时&#xff0c;其格式是&#xff1a; typedef 新类型名 原类型名; B 在程序中&#xff0c;允许用typedef来说明一种新的类型名 C 使用typedef 说明新类型名时&#xff0c;后面不能加分号 D 在使用typ…

three.js学习 06 - 结合GSAP(补间动画)设置各种动画效果(运动效果与双击暂停动画等效果)

1. GSAP简介 GSAP&#x1f44d;&#x1f3fc;是前端业内非常有名的一个动效库&#xff0c;有大量的优秀的网站都在使用它。它不仅能在原生JS的环境下使用&#xff0c;也能配合各种当前流行的框架进行使用。 通过使用它&#xff0c;非常多原本实现起来很有难度的交互动画效果&a…

计算机必读基础书籍

计算机必读数据 一&#xff1a;故事背景1.1 前言1.2 提示 二&#xff1a;计算机组成2.1 是什么2.2 有什么2.2.1 计算机系统概述2.2.2 数据信息的表示2.2.3 运算方法与运算器2.2.4 存储系统2.2.5 指令系统2.2.6 中央处理器2.2.7 指令流水线2.2.8 总线系统2.2.9 输入输出 2.3 思维…

[MAY DAY]五一综合训练 之——最值问题

文章目录 > **## * 要赋值 &#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; *** %#&#xffe5;#%#*&&#xff01;&#xff01;&#xff01;&#xff01;要赋值一、双指针求最大连续和双指针算法分析&#xff1a; 注意&#xff…

Java学习笔记-03

目录 类与对象 类class 对象 修饰符private this关键字 构造函数 继承 权限修饰符 包package 状态修饰符final 类与对象 类 类是对现实生活中一类事物的抽象&#xff0c;里面包含了这类事物共有的属性(名词)和行为(动词)例如人类&#xff0c;人就是一个大类&#xff…

大规模MIMO系统中基于CSI的卷积神经网络定位

来源&#xff1a;投稿 作者&#xff1a;小灰灰 编辑&#xff1a;学姐 论文标题&#xff1a;CSI-based Positioning in Massive MIMO systems using Convolutional Neural Networks 摘要 研究了使用大规模MIMO&#xff08;MaMIMO&#xff09;系统的信道状态信息&#xff08;CS…

mysql 基础操作命令集

目录 目录 数据库操作 查看库命令 使用某个库&#xff08;可以不用分号 &#xff1b;&#xff09; 查看库下所有的表 显示一个表下的所有字段和类型 查看一个表的建表语句 查看表的内容 创建新数据库 创建新表&#xff0c;设定表的字段 插入一行数据 某字段更改数据…

OSI七层模型及各层功能概述

1.OSI的基本概念及原则 OSI是Open System Interconnect的缩写&#xff0c;意为开放式系统互联。其各个层次的划分遵循下列原则&#xff1a; &#xff08;1&#xff09;同一层中的各网络节点都有相同的层次结构&#xff0c;具有同样的功能。&#xff08;2&#xff09;同一节点…

运营商大数据是什么,是如何实现精准获客的

近年来&#xff0c;运营商大数据在市场之上发展迅速&#xff0c;各行各业的公司都在利用运营商大数据获取更加精准有效的企业信息和客户资源。例如&#xff0c;当企业在进行精准营销的过程之中&#xff0c;可以根据线索和条件快速获得更准确的客户名单&#xff0c;而不像传统的…

定时任务方案实现与对比

定时任务分类 定时任务分为分布式定时任务和单机定时任务两个大的方向&#xff0c;他们的适用场景不同。 单机定时任务在单台计算机上运行&#xff0c;其执行结果和单台机器上的数据有关&#xff0c;如对本地机器的缓存做核对、清理日志等。它的 优点 是简单易用&#xff0c;无…

玩着3dmax把Python学了-01

3ds Max 2022以前的版本要借助Python的api来实现Python编程达到编辑绘图脚本的功能&#xff0c;但是好消息来了&#xff0c;3ds Max 2022 起&#xff0c;MaxPlus 不再作为 3ds Max 的 Python API 包含在内。而是3ds Max 将 Python 3.7 的标准版本包涵其中了&#xff0c;位于 [3…

MySQL监控告警及可视化:Zabbix+Percona PMP实现(Part II)

MySQL监控告警及可视化&#xff1a;ZabbixPercona PMP实现&#xff08;Part II&#xff09; PMP插件安装PMP监控脚本配置Web界面导入PMP模板 服务器清单如下&#xff1a; 服务器IP配置OS版本服务器角色172.16.175.x4c8gCentOS 7.7MySQL Server172.16.175.y4c8gCentOS 7.7Zabbi…

Python——基于YOLOV8的车牌识别(源码+教程)

目录 一、前言 二 、完成效果 三、 项目包 四、运行项目 &#xff08;教程&#xff09; 一、前言 YOLOv8LPRNet车牌定位与识别https://www.bilibili.com/video/BV1vk4y1E7MZ/ 最近做了有一个车牌识别的小需求&#xff0c;今天完成了&#xff0c;在此记录和分享 首先&#x…

NECCS|全国大学生英语竞赛C类|听力|短篇新闻|听写填空|16:40~17:10+17:30~18:10

目录 一、听写填空 1. 题型 2. 技巧 &#xff08;1&#xff09;利用间隙 浏览全文 积极预测 &#xff08;2&#xff09;边听边记 &#xff08;3&#xff09;注重检查 二、短篇新闻 1. 试题解读 2. 解题技巧 &#xff08;1&#xff09;预测要点&#xff0c;有的放矢 …

【五一创作】机械臂速成小指南(二十四):逆运动学的雅可比方法

&#x1f468;‍&#x1f3eb;&#x1f970;&#x1f973;需要机械臂相关资源的同学可以在评论区中留言哦&#x1f916;&#x1f63d;&#x1f984; 指南目录&#x1f4d6;&#xff1a; &#x1f389;&#x1f389;机械臂速成小指南&#xff08;零点五&#xff09;&#xff…

Redis消息队列

消息队列&#xff08;Message Queue&#xff09;&#xff0c;字面意思就是存放消息的队列。最简单的消息队列模型包括3个角色&#xff1a; 消息队列&#xff1a;存储和管理消息&#xff0c;也被称为消息代理&#xff08;Message Broker&#xff09; 生产者&#xff1a;发送消…

【hello Linux】线程概念

目录 1. 线程概念的铺设 2. Linux线程概念 2.1 什么是线程 2.2 线程的优点 2.3 线程的缺点 2.4 线程异常 2.5 线程用途 3. Linux进程VS线程 4. Linux线程控制 4.1 POSIX线程库 4.2 创建线程 4.3 进程ID和线程ID 4.4 线程终止 4.5 线程等待 4.6 分离线程 Linux&#x1f337; 1…