代理模式(十五)

news2024/11/26 21:41:05

相信自己,请一定要相信自己

上一章简单介绍了享元模式(十四), 如果没有看过, 请观看上一章

一. 代理模式

引用 菜鸟教程里面的代理模式介绍: https://www.runoob.com/design-pattern/proxy-pattern.html

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

一.一 介绍

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

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

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

如何解决: 增加中间层。

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

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

优点: 1、职责清晰。 2、高扩展性。 3、智能化。

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

使用场景: 按职责来划分,通常有以下使用场景: 1、远程代理。 2、虚拟代理。 3、Copy-on-Write 代理。 4、保护(Protect or Access)代理。 5、Cache代理。 6、防火墙(Firewall)代理。 7、同步化(Synchronization)代理。 8、智能引用(Smart Reference)代理。

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

在这里插入图片描述

二. 代理模式

有 静态代理, 动态代理 (JDK代理) 和 Cglib 代理 ( 可以在内存动态的创建对象)

二.一 静态代理

二.一.一 教师讲课的接口

public interface ITeacher {

    public void talk();
}

二.一.二 一个教师讲课的接口实现

@Slf4j
public class RealTeacher implements ITeacher{

    @Override
    public void talk() {
        log.info("老师正在讲课");
    }
}

二.一.三 不使用代理

 @Test
    public void noProxyTest() {
        ITeacher iTeacher = new RealTeacher();
        iTeacher.talk();
    }

INFO [main] (RealTeacher.java:16) - 老师正在讲课

二.一.四 使用代理

@Slf4j
public class TeacherProxy implements ITeacher{
    private ITeacher iTeacher ;

    public TeacherProxy (ITeacher iTeacher) {
        this.iTeacher = iTeacher;
    }

    @Override
    public void talk() {
        log.info("老师提前备课--> 用户 prepare 操作");
        iTeacher.talk();
        log.info("老师课后总结--> 用户 after 操作");
    }

}

二.一.五 代理测试方法

@Test
    public void oneTest() {
        RealTeacher realTeacher = new RealTeacher();
        TeacherProxy teacherProxy = new TeacherProxy(realTeacher);
        teacherProxy.talk();
    }

image-20230615145810997

二.二 动态代理

二.二.一 接口

public interface ITeacher2 {

    public void talk();

    public void hello (String name);
}

二.二.二 接口实现

@Slf4j
public class RealTeacher2 implements ITeacher2{

    @Override
    public void talk() {
        log.info("老师正在讲课");
    }

    @Override
    public void hello(String name) {
        log.info("你好啊 {}", name);
    }
}

二.二.三 JDK 代理实现

@Slf4j
public class TeacherProxy2 {

    private Object target ;

    public TeacherProxy2 (Object target) {
        this.target = target;
    }

    /**
     获取动态代理
     */
    public Object getProxyInstance() {
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        log.info("JDK代理开始");

                        Object returnVal = method.invoke(target, args);

                        log.info("JDK代理结束");
                        return returnVal;
                    }
                }
        );
    }

}

二.二.四 代理测试

   @Test
    public void twoTest() {
        ITeacher2 teacher2 = new RealTeacher2();
        // 处理转换代理信息
        ITeacher2 target = (ITeacher2)(new TeacherProxy2(teacher2).getProxyInstance());
        // 进行处理
        target.hello("张三");
    }

image-20230615150102593

二.三 Cglib 代理

二.三.一 一个普通的类

@Slf4j
public class RealTeacher3 {

    public void talk() {
        log.info("老师正在讲课");
    }

    public void hello(String name) {
        log.info("你好啊 {}", name);
    }
}

二.三.二 对该类进行代理 TeacherProxy3

@Slf4j
public class TeacherProxy3 implements MethodInterceptor {
    private Object target;
    public TeacherProxy3(Object target) {
        this.target = target;
    }
    
    public Object getProxyInstance () {
        // 创建工具类 Enhancer
        Enhancer enhancer = new Enhancer();
        // 设置父类
        enhancer.setSuperclass(target.getClass());
        // 设置回调函数, 主要是这个。
        enhancer.setCallback(this);
        // 创建子类对象,即代理对象
        return enhancer.create();
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        log.info("CGLIB 代理开始");

        Object returnVal = methodProxy.invoke(target, objects);

        log.info("CGLIB 代理结束");
        return returnVal;
    }

}

二.三.三 代理测试

@Test
    public void threeTest() {
        RealTeacher3 realTeacher3 = new RealTeacher3();
        // 处理转换代理信息
        RealTeacher3 target = (RealTeacher3)new TeacherProxy3(realTeacher3).getProxyInstance();
        // 进行处理
        target.hello("张三");
    }

image-20230615150340055

三. Hutool 的 JDK 代理

可以使用 hutool 的 ProxyUtil ProxyFactory 进行代理

@Test
    public void fourTest() {
        ITeacher2 teacher2 = new RealTeacher2();

        ITeacher2 proxy = ProxyUtil.proxy(teacher2, new SimpleAspect());

        proxy.hello("hutool 工具类的代理");

        ITeacher2 proxy2 = ProxyFactory.createProxy(teacher2, new Aspect() {
            @Override
            public boolean before(Object target, Method method, Object[] args) {
                log.info(">>>> 代理之前执行的操作");
                return true;
            }

            @Override
            public boolean after(Object target, Method method, Object[] args, Object returnVal) {
                log.info(">>>> 代理之后执行的操作");
                return true;
            }

            @Override
            public boolean afterException(Object target, Method method, Object[] args, Throwable e) {
                log.info(">>>> 异常时执行的操作");
                return true;
            }
        });
        proxy2.hello("hutool 工厂的代理");
    }

image-20230615150904736

CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。

所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。

同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理


本章节的代码放置在 github 上:


https://github.com/yuejianli/DesignPattern/tree/develop/Proxy


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

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

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

相关文章

阿里云服务器租用费用_2023价格表

2023年阿里云服务器租用费用,阿里云轻量应用服务器2核2G3M带宽轻量服务器一年108元,2核4G4M带宽轻量服务器一年297.98元12个月,阿里云u1服务器2核4G、2核8G、4核8G、8核16G、4核16G、8核64等配置新人3折,云服务器c7、g7和r7均有活…

责任链模式:构建一条责任链去处理不同级别的日志信息

概要 责任链模式(Chain of Responsibility Pattern)是一种行为型设计模式,在有多个对象(处理者)都可以接收请求的情况下,允许你将多个对象连接成一条处理链,请求沿着处理链进行发送。收到请求后…

最新水文水动力模型在城市内涝、城市排水、海绵城市规划设计中深度应用丨SWMM排水管网水力、水质建模及海绵与水环境应用

目录 第一部分 CAD、GIS在水力建模过程中的应用 第二部分 SWMM模型深度应用 第三部分 城市内涝一维二维耦合模拟 第四部分 海绵城市关键控制指标计算 第五部分 SWMM二次开发基础 SWMM排水管网水力、水质建模及在海绵与水环境中的应用 随着计算机的广泛应用和各类模型软件…

基于AutoJs7实现的薅羊毛App专业版源码大分享

源码下载链接:https://pan.baidu.com/s/1QvalXeUBE3dADfpVwzF_xg?pwd0736 提取码:0736 专业版肯定比个人版功能强大并且要稳定。增加了很多功能的同时也测试封号的App,对于封号的App,给予剔除。虽然App数量减少了但是都是稳定的…

getopt函数和getopt_long函数

这个函数有点像无限迷宫,正确的路和错误的路都有很多,我们只需要能够满足当前需求就可以了,完全没有必要去探索每一条路。虽然,我很久以前试图这样干过。过滤后的回忆,只剩感觉了,过滤的多了,感…

阿里巴巴开源的Spring Cloud Alibaba手册在GitHub上火了

“微服务架构经验你有吗?” 前段时间一个朋友去面试,阿里面试官一句话问倒了他。实际上,不在BAT这样的大厂工作,是很难接触到支撑千亿级流量微服务架构项目的。但也正是这种难得,让各个大厂都抢着要这样的人才&#x…

高校如何拿下数据分类分级这道“题”? 建设方案与实践来了

数据安全若一场“大考”,数据分类分级绝对是道“必答题”。 对高校而言,同样如此。作为高层次人才培养与科学研究的重要基地,高校既拥有高价值的科研等敏感数据,又涉及大量师生个人信息,无论是开展数据战略还是数据安全…

35岁以上的测试人员有多少?

今天在某论坛上看到一个有意思的问题:35岁以上的测试人员有多少? 细细一琢磨,为什么这位朋友会有这样的疑问呢?根据提问者的年龄划分,有以下两种可能: 35岁以下的提问者:想了解下35岁是否真如…

第八章 Electron 实现音乐播放器之爬虫播放音乐

一、介绍 🚀 ✈️ 🚁 🚂 我在第五章已经有一篇Electron爬虫的文章,主要写的爬取图片资源的案例。这篇开始讲解如何到一个音乐网站爬取音乐资源,并且进行在线播放,下载等等。 那么什么是爬虫呢。百度百科上…

今日小课堂:怎么翻译音频

想象一下,你正在与外国朋友聊天,但是你们之间有语言障碍。不用担心!现在有许多翻译语音识别工具可以帮助你轻松应对这种情况。通过这些工具,你可以将语音转换为文字,然后再将其翻译成你所需的语言。接下来,…

会声会影2023中文版本V26.0.0.136

会声会影2023中文版是一款功能强大的视频编辑软件、大型视频制作软件、专业视频剪辑软件。会声会影专业视频编辑处理软件,可以用于剪辑合并视频,制作视频,屏幕录制,光盘制作,视频后期编辑、添加特效、字幕和配音等操作…

爬虫一定要用代理IP吗,不用行不行

目录 1、爬虫一定要用代理IP吗 2、爬虫为什么要用代理IP 3、爬虫怎么使用代理IP 4、爬虫使用代理IP的注意事项 1、爬虫一定要用代理IP吗 很多人觉得,爬虫一定要使用代理IP,否则将寸步难行。但事实上,很多小爬虫不需要使用代理IP照样工作…

【TA100】3.4 前向/延迟渲染管线介绍

一、渲染路径 1.什么是渲染路径(Rendering Path) ● 是决定光照实现的方式。(也就是当前渲染目标使用的光照流程) 二、渲染方式 首先看一下两者的直观的不同 前向/正向渲染-Forward Rendering 一句话概括:每个光…

openpose原理以及各种细节的介绍

前言: OpenPose是一个基于深度学习的人体姿势估计库,它可以从图像或视频中准确地检测和估计人体的关键点和姿势信息。OpenPose的目标是将人体姿势估计变成一个实时、多人、准确的任务。——本节介绍openpose的原理部分 把关键点按照定义好的规则从上到下…

Matter实战系列-----5.matter设备证书烧录

一、安装工具 1.1 安装Commander_Linux工具 下载地址 https://www.silabs.com/documents/public/software/SimplicityCommander-Linux.zip 下载完之后解压缩,在压缩包内执行命令如下 tar jxvf Commander_linux_x86_64_1v15p0b1306.tar.bz cd ./commander ./co…

启动appium服务的2种方法(python脚本cmd窗口)

目录 前言: 1. 通过cmd窗口命令启动 1.1 启动单个appium服务 1.2 启动多个appium服务 2. 通过python脚本来启动 2.1 启动单个appium服务 2.2 启动多个appium服务 3. 启动校验 3.1 通过cmd命令查看 3.1.1 查看指定端口号 3.1.2 查看全部端口号 3.2 通过生…

华为笔记本怎么用U盘重装Win10系统?

华为笔记本怎么用U盘重装Win10系统?华为笔记本拥有指纹识别、背光键盘、信号增强等功能,带给用户超棒的操作体验,用户现在想用U盘来重装华为笔记本Win10系统,但不知道具体怎么操作,这时候用户就可以按照以下分享的华为…

CMAC算法介绍

文章目录 一、简介二、符号三、步骤3.1 子秘钥生成3.2 计算MAC值 一、简介 CMAC(Cipher Block Chaining-Message Authentication Code),也简称为CBC_MAC,它是一种基于对称秘钥分组加密算法的消息认证码。由于其是基于“对称秘钥分…

网络安全|渗透测试入门学习,从零基础入门到精通—渗透中的开发语言

目录 前面的话 开发语言 1、html 解析 2、JavaScript 用法 3、JAVA 特性 4、PHP 作用 PHP 能做什么? 5、C/C 使用 如何学习 前面的话 关于在渗透中需要学习的语言第一点个人认为就是可以打一下HTML,JS那些基础知识,磨刀不误砍柴…

RTU遥测终端机的应用场景有哪些?

遥测终端机又称智能RTU遥测终端机,是一种用于采集、传输和处理遥测数据的设备。在现代科技的发展中,遥测终端机扮演着重要的角色。它是一种能够实现远程监测和控制的关键设备,广泛应用于各个领域,包括水文水利、环境监测、工业自动…