Java特性之设计模式【代理模式】

一、代理模式

概述

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

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

主要解决

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

何时使用

想在访问一个类时做一些控制

优缺点

优点:

  • 职责清晰
  • 高扩展性
  • 智能化

缺点:

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

注意事项

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

1. 各个角色介绍

1.1 抽象主题(Subject)

  • 定义了真实主题和代理主题的共同接口,这样在任何使用真实主题的地方都可以使用代理主题

1.2 真实主题(Real Subject)

  • 实现了抽象主题接口,是代理对象所代表的真实对象。客户端直接访问真实主题,但在某些情况下,可以通过代理主题来间接访问

1.3 代理(Proxy)

  • 实现了抽象主题接口,并持有对真实主题的引用。代理主题通常在真实主题的基础上提供一些额外的功能,例如延迟加载、权限控制、日志记录等

2. UML图

​ 我们将创建一个 ILandlordService 租房接口和实现了 ILandlordService 接口的实体类。AgentProxy 是一个代理类,减少房东 HostServiceImpl 对象加载的内存占用

在这里插入图片描述

3. 具体例子和代码

角色分配

  • ILandlordService:租房接口
    • HostServiceImpl:房东实现类
    • AgentProxy:中介代理

3.1 租房接口及其实现类

  • ILandlordService
package com.vinjcent.prototype.proxy;

/**
 * @author vinjcent
 * @description 租房接口
 * @since 2024/3/27 17:52
 */
public interface ILandlordService {


    /**
     * 出租
     *
     * @param money 金额
     */
    void rent(Integer money);


}

  • HostServiceImpl
package com.vinjcent.prototype.proxy;

/**
 * @author vinjcent
 * @description 房东实现类(实现)
 * @since 2024/3/27 17:55
 */
public class HostServiceImpl implements ILandlordService {

    @Override
    public void rent(Integer money) {
        System.out.println("房东处理...");
        System.out.println("出租" + money + "元一个月的房子");
    }

    @Override
    public String toString() {
        return "HostServiceImpl{}";
    }
}

  • AgentProxy
package com.vinjcent.prototype.proxy.static_proxy;

import com.vinjcent.prototype.proxy.HostServiceImpl;
import com.vinjcent.prototype.proxy.ILandlordService;

/**
 * @author vinjcent
 * @description 中介代理
 * @since 2024/3/27 18:04
 */
public class AgentProxy implements ILandlordService {

    /**
     * 被代理的对象
     */
    private ILandlordService target;


    @Override
    public void rent(Integer money) {
        if (target == null) {
            target = new HostServiceImpl();
        }
        System.out.println("中介处理...");
        target.rent(money);
    }
}

3.2 额外拓展(动态代理:JDK动态代理、CGLib动态代理)

3.2.1 JDK动态代理

JDK动态代理的代理类根据目标实现的接口动态生成,不需要自己编写,生成的动态代理类和目标类都实现相同的接口,JDK动态代理的核心是InvocationHandler接口和Proxy类,缺点是目标类必须有实现接口,如果某个目标类没有实现接口,那么这个类就不能用JDK动态代理

  • JDKProxyFactory
package com.vinjcent.prototype.proxy.dynamic_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author vinjcent
 * @description JDK动态代理
 * @since 2024/3/27 17:24
 */
public class JDKProxyFactory implements InvocationHandler {

    /**
     * 需要被代理的对象
     */
    private final Object object;

    public JDKProxyFactory(Object object) {
        this.object = object;
    }

    @SuppressWarnings("unchecked")
    public <T> T getProxy() {
        Object o = Proxy.newProxyInstance(
                // 当前线程的上下文ClassLoader
                Thread.currentThread().getContextClassLoader(),
                // 代理对象实现的接口
                this.object.getClass().getInterfaces(),
                // 处理器自身
                this
        );

        return (T) o;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = new Object();
        // 进行方法匹配,调用对应方法名的方法
        if ("rent".equals(method.getName())) {
            System.out.println("JDK动态代理前置增强");
            result = method.invoke(object, args);
            System.out.println("JDK动态代理后置增强");
        }

        return result;

    }

    @Override
    public String toString() {
        return "JDKProxyFactory{" +
                "object=" + object +
                '}';
    }
}

3.2.2 CGLib动态代理

在程序运行时动态生成类的字节码,动态创建目标类的子类对象,在子类对象中增强目标类,CGLib是通过继承的方式实现的动态代理,因此如果某个类被标记为final,它是无法使用CGLib做动态代理的,优点在于不需要实现特定的接口,更加灵活

在这里插入图片描述

  • CglibProxyFactory
package com.vinjcent.prototype.proxy.dynamic_proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author vinjcent
 * @description CGLib动态代理
 * @since 2024/3/27 22:42:16
 */
public class CglibProxyFactory implements MethodInterceptor {

    @SuppressWarnings("unchecked")
    public <T> T getProxy(Class<T> clazz) {
        // Enhancer是CGLIB库中用于动态生成子类的主要类.通过创建Enhancer对象并设置需要代理的目标类、拦截器等参数,可以生成一个代理类
        Enhancer en = new Enhancer();
        // 设置代理的父类
        en.setSuperclass(clazz);
        // 设置方法回调
        en.setCallback(this);
        Object o = en.create();
        // 创建代理实例.通过调用Enhancer对象的create方法,可以生成一个代理对象.代理对象会继承目标类的方法,并且在调用代理对象的方法时会先调用拦截器的intercept方法,再执行目标方法
        return (T) en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        // 在生成代理类时,需要指定拦截器.拦截器是实现代理逻辑的关键,它会在代理类的方法被调用时拦截调用,并执行相应的逻辑

        Object result = null;
        System.out.println("CGLIB动态代理前置增强");
        // 通过调用代理对象的方法,会触发拦截器的intercept方法.在intercept方法中,可以根据需要执行各种逻辑,比如添加日志、性能统计、事务管理等
        if ("rent".equals(method.getName())) {
            // 通过继承的方法实现代理,因此这里调用invokeSuper
            result = methodProxy.invokeSuper(o, args);
        }
        System.out.println("CGLIB动态代理后置增强");

        return result;

    }
}

3.3 测试主函数

package com.vinjcent.prototype.proxy;

import com.vinjcent.prototype.proxy.dynamic_proxy.CglibProxyFactory;
import com.vinjcent.prototype.proxy.dynamic_proxy.JDKProxyFactory;
import com.vinjcent.prototype.proxy.static_proxy.AgentProxy;

/**
 * @author vinjcent
 * @description 代理模式
 * @since 2024/3/27 18:01
 */
public class Main {


    public static void main(String[] args) {

        System.out.println("静态代理");
        // 静态代理
        ILandlordService landlordService = new AgentProxy();
        System.out.println("第一次代理调用目标类方法");
        landlordService.rent(20);
        System.out.println("\n第二次代理调用目标类的方法");
        landlordService.rent(25);
        System.out.println("\n");

        HostServiceImpl hostService = new HostServiceImpl();
        System.out.println("JDK动态代理");
        // JDK动态代理
        ILandlordService jdkProxy = new JDKProxyFactory(hostService).getProxy();
        jdkProxy.rent(750);

        System.out.println("\n");

        System.out.println("CGLib动态代理");
        // CGLIB动态代理
        HostServiceImpl cglibProxy = new CglibProxyFactory().getProxy(hostService.getClass());
        cglibProxy.rent(750);
    }

}

  • 测试结果

在这里插入图片描述

4. 使用场景

  • 远程代理
  • 虚拟代理
  • Copy-on-Write 代理
  • 保护(Protect or Access)代理
  • Cache代理
  • 防火墙(Firewall)代理
  • 同步化(Synchronization)代理
  • 智能引用(Smart Reference)代理

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入了解 NumPy:深度学习中的数学运算利器

文章目录 1. 导入NumPy2. 创建NumPy数组3. 数组的算术运算4. N维数组4.1 创建和操作多维数组4.2 高维数组 5. NumPy的广播功能5.1 基本广播示例5.2 更复杂的广播示例 6. 访问数组元素6.1 基于索引的访问6.2 遍历数组6.3 基于条件的访问6.4 高级索引6.5 性能考虑 在深度学习和数…

论文阅读_使用有向无环图实现流程工程_AgentKit

英文名称: AgentKit: Flow Engineering with Graphs, not Coding 中文名称: AgentKit&#xff1a;使用图而非编码进行流程工程 链接: https://arxiv.org/pdf/2404.11483.pdf 代码: https://github.com/holmeswww/AgentKit 作者: Yue Wu, Yewen Fan, So Yeon Min, Shrimai Prabh…

射频无源器件之耦合器

一. 耦合器的作用 在射频电路中,射频耦合器将一路微波功率按比例分成几路,用于检测或监测信号,如功率测量和波检测,还可改变信号的幅度、相位等特性,以满足不同的通信需求。根据输入与耦合端的功率差,常被分为5dB、6dB、10dB等耦合器。射频耦合器的类型主要包括定向耦合…

区块链 | NFT 相关论文:Preventing Content Cloning in NFT Collections(三)

&#x1f436;原文&#xff1a; Preventing Content Cloning in NFT Collections &#x1f436;写在前面&#xff1a; 这是一篇 2023 年的 CCF-C 类&#xff0c;本博客只记录其中提出的方法。 F C o l l N F T \mathbf{F_{CollNFT}} FCollNFT​ and Blockchains with Native S…

命名空间、C++的输入输出、缺省参数(默认参数)、函数重载

&#x1f436;博主主页&#xff1a;ᰔᩚ. 一怀明月ꦿ ❤️‍&#x1f525;专栏系列&#xff1a;线性代数&#xff0c;C初学者入门训练&#xff0c;题解C&#xff0c;C的使用文章&#xff0c;「初学」C&#xff0c;linux &#x1f525;座右铭&#xff1a;“不要等到什么都没有了…

基于Springboot的校园健康驿站管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园健康驿站管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

TMS320F2812DSP最小系统原理图及PCB文件

目录 1、原理图 2、PCB 资料下载地址&#xff1a;TMS320F2812DSP最小系统原理图及PCB文件 1、原理图 2、PCB

视频转GIF动图:一键批量操作技巧,轻松实现动态图像转换

在数字媒体时代&#xff0c;GIF动图因其小巧、循环播放的特性&#xff0c;在网络传播中占据了重要地位。而将视频转换为GIF动图&#xff0c;不仅可以快速捕捉视频中的精彩瞬间&#xff0c;还能为社交媒体、网站和博客等内容创作增添生动与活力。本文将介绍如何通过一键批量操作…

三、VGA接口驱动与图像显示动态移动

文章目录 一、参数介绍二、彩条显示2.1 模块系统架构框图2.2 行、场同步波形:2.3 代码三、VGA 图像显示动态移动3.1波形设计3.2代码 一、参数介绍 对于普通的 VGA 显示器&#xff0c;共有 5 个信号&#xff1a;R、G、B 三基色&#xff1b;HS&#xff08;行同步信号&#xff09…

Mysql基础(五)外键约束

一 外键 激励&#xff1a; 每天进步一点点即可 ① 思考 1、在MySQL中,我们知道主键 PRIMARY KEY的主要作用是唯一区分表中的各个行 [记录];思考&#xff1a;但是对于外键 foreign key比较陌生? 那么外键作用以及限制条件和目的呢? ② 外键的定义 1、外键是某个表 A中…

第一天复习Qt文件读取

Qt文件操作&#xff1a; 1、QFile QTextStream操作文件案例&#xff1a; 1、打开文件 QFile file(absolute filepath | relative path); file.readLine()返回内容长度&#xff0c;如果为-1就是读取失败 file. Close()读取后关闭 file.errorString()返回文件打开发生的错误2、…

如何购买阿里云99计划的ECS云服务器?99元购买阿里云2核2G3M服务器教程

阿里云助力中小企业和开发者无忧上云的“99计划”中有两款性价比超高的ECS云服务器&#xff0c;2026年3月31日活动结束前新购和续费价格一样。 其中个人和企业新老用户同享的2核2G3M服务器仅需99元/年&#xff08;续费同价&#xff09;&#xff0c;企业新老用户同学的2核4G5M仅…

外贸企业6大客户开发渠道优缺点全面解析 | 箱讯科技国际贸易综合服务平台

一、展会的重要性 展会&#xff0c;作为历史悠久的客户开发渠道&#xff0c;一直备受企业推崇。它汇聚了来自不同行业的企业&#xff0c;为大家提供了一个集中展示产品和技术的大舞台。在没有互联网的年代&#xff0c;展会几乎成为外贸交易的核心媒介。至今&#xff0c;它依然…

射频无源器件之巴伦

一. 巴伦的作用 Balun,balanced-unbalanced的缩写,即平衡-不平衡转换器,是一种三端口无源器件,其本质是通过电感线圈的相互耦合实现的信号转换。用于平衡信号(差分信号,即振幅相等、相位相差180 的两个信号)与非平衡信号(单端信号)的相互转换。 Balun是高频电路重要器…

《编译原理》阅读笔记:p1-p3

《编译原理》学习第 1 天&#xff0c;p1-p3总结&#xff0c;总计 3 页。 一、技术总结 1.compiler(编译器) p1, But, before a program can be run, it first must be translated into a form in which it can be executed by a computer. The software systems that do thi…

水面垃圾清理机器人的视觉算法研究

卷积神经网络是一种分层的数据表示模型&#xff0c;通常由数据输入层、卷积层、池化层、 非线性激活函数、全连接层以及输出结果预测层等组成&#xff0c;其中卷积层、池化层和非线 性激活函数是卷积神经网络中的重要组成部分。此外&#xff0c;有些模型会增加其他的层(归一 化…

16.接口自动化学习-编码处理与装饰器

1.编码和解码 编码&#xff1a;将自然语言翻译成计算机可以识别的语言 hello–01010 解码&#xff1a;将机器识别的语言翻译成自然语言 2.编码格式 UTF-8 GBK unicode 3.编码操作 #编码操作str1"hello呀哈哈哈"str2str1.encode(gbk)print(str2)print(type(str2))…

面试笔记——多线程使用场景

线程池使用场景&#xff08;CountDownLatch&#xff0c; Future&#xff09; CountDownLatch CountDownLatch&#xff08;闭锁/倒计时锁&#xff09;用来进行线程同步协作&#xff0c;等待所有线程完成倒计时&#xff08;一个或者多个线程&#xff0c;等待其他多个线程完成某件…

漏扫神器Invicti V2024.4.0专业版

前言 Invicti Professional是Invicti Security公司推出的一个产品&#xff0c;它是一种高级的网络安全扫描工具。Invicti Professional旨在帮助组织发现和修复其网络系统中的潜在安全漏洞和弱点。它提供了全面的漏洞扫描功能&#xff0c;包括Web应用程序和网络基础设施的漏洞扫…

2024 GESP6级 编程第一题 游戏

题目描述 你有四个正整数 &#xff0c;并准备用它们玩一个简单的小游戏。 在一轮游戏操作中&#xff0c;你可以选择将 减去 &#xff0c;或是将 减去 。游戏将会进行多轮操作&#xff0c;直到当 时游戏结束。 你想知道游戏结束时有多少种不同的游戏操作序列。两种游戏操作…
最新文章