Java设计模式 _结构型模式_代理模式(静态,动态)

一、基础概念

1、代理模式
代理模式(Proxy Pattern)是一种结构型设计模式。它允许我们通过添加一个代理对象来控制对另一个对象的访问,从而实现一些额外的功能,如访问控制、日志记录、性能监控等。代理模式主要分为静态代理和动态代理两种。

2、静态代理
静态代理是指由程序员创建或工具生成代理类的源码,再编译代理类。代理类和委托类在运行前就确定了关系,且这种关系在运行期不能被改变。
优点:
可以在不修改目标对象的前提下,对目标对象的功能进行扩展。
代理类和目标对象实现相同的接口,因此具有相同的方法签名,这使得代理类可以无缝地替换目标对象。
缺点:
如果需要代理的目标类很多,那么就需要编写大量的代理类,这会导致代码冗余和难以维护。
一旦接口增加方法,目标对象与代理对象都需要进行维护。

3、动态代理
动态代理是指在程序运行期间,根据反射等机制动态地生成代理类的源码,并加载到JVM中。动态代理的源码在程序运行期间生成,因此不存在代理类的字节码文件。
优点:
无需手动编写代理类,减少了代码冗余和提高了可维护性。
适用于目标对象接口不确定或需要频繁变更的场景。
可以实现更复杂的代理逻辑,如AOP(面向切面编程)等。
缺点:
由于动态代理是基于反射实现的,因此相对于静态代理来说,性能上可能稍逊一筹。
动态代理只能代理实现了接口的类,不能代理实现了抽象类或继承了具体类的对象。

4、InvocationHandler
InvocationHandler 是一个接口,它是动态代理模式的核心部分。当使用 Proxy 类和 InvocationHandler 接口来创建动态代理时,你实际上是在创建一个实现了指定接口的代理类实例,该实例在方法调用时会转发到 InvocationHandler 的 invoke 方法。

5、静态代理实现思路
(1)、定义规范接口
(2)、编写实现类1,实现上诉规范接口
(3)、编写代理类,实现上诉规范接口,同时将实现类注入为代理类的成员属性,编写构造方法或其他方法实例化这个成员属性。
(4)、编写代理类的实现方法,通过引用成员实现类的相同方法实现,可以在前后进行相关的业务扩展。
(5)、生成代理对象,执行业务方法

6、动态代理实现思路
(1)、定义规范接口
(2)、编写实现类1,实现上诉规范接口
(3)、编写InvocationHandler接口的实现方法,扩展业务需要,如之前过滤数据,之后记录日志等。
(4)、通过Proxy对象和实现的InvocationHandler类创建目标对象的代理对象
(5)、调用代理对象,执行业务方法

二、代码示例

1、静态代码示例

// 1、定义规范接口
public interface CarApply {
    public void useCar(String user,String date);
}
// 2、创建实现类
public class EmployeeCarApply implements CarApply{
    @Override
    public void useCar(String user, String date) {
        System.out.println(user+"在"+date+"申请用车");
    }
}
// 3、创建代理类
public class ProxyCarApply implements CarApply {

    private CarApply carApply;

    public ProxyCarApply(CarApply carApply) {
        this.carApply = carApply;
    }

    @Override
    public void useCar(String user, String date) {
        if (user.contains("经理")) {
            System.out.println(date + "给" + user + "安排一名司机");
        }
        carApply.useCar(user, date);
        if (user.contains("经理")) {
            System.out.println("2个小时后给" + user + "订餐");
        }
    }
}
// 测试
public static void main(String[] args) {
        EmployeeCarApply employeeCarApply1 = new EmployeeCarApply();
        employeeCarApply1.useCar("李四经理","2024年3月15日");
        System.out.println();

        ProxyCarApply proxyCarApply = new ProxyCarApply(new EmployeeCarApply());
        proxyCarApply.useCar("李四经理","2024年3月16日");
    }

运行结果:
直接用目标类仅做了基础功能,通过代理类在执行目标类的功能前后做了一些前置和后置的业务扩展。
在这里插入图片描述

2、动态代码示例

// 1、定义规范接口
public interface CarApply {
    void useCar(String user, String date);
}
// 2、创建实现类
public class EmployeeCarApply implements CarApply {
    @Override
    public void useCar(String user, String date) {
        System.out.println(user+"在"+date+"申请用车");
    }
}
// 3、创建InvocationHandler的实现类,标识动态代理,进行接口功能转发到本类的invoke方法上
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class CarApplyInvocationHandler implements InvocationHandler {
    private Object target;
    public CarApplyInvocationHandler(Object target){
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("调用之前的逻辑");
        Object result = method.invoke(target, args);   // 执行真实的方法
        System.out.println("调用之后的逻辑");
        return result;
    }
}
// 4、创建Proxy的代理工厂,通过此工厂动态生成代理对象
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class ProxyFactory {
    public static <T> T getProxyInstance(Object target){
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler handler = new CarApplyInvocationHandler(target);
        return (T) Proxy.newProxyInstance(classLoader,interfaces,handler);
    }
}
// 5、测试
public static void main(String[] args) {
        CarApply proxyObj = ProxyFactory.getProxyInstance(new EmployeeCarApply());
        proxyObj.useCar("张三","2023年3月17日");
    }

运行结果:
由下结果可以看出,当执行代理对象的业务方法时,之际执行了InvocationHandler实现类的invoke方法。
在这里插入图片描述

3、总结
代理的作用就是在不改变原代码的同时,对原代码的功能做业务扩展。分为静态和动态两种代理方式,静态代理需要我们在开发过程中就先创建好代理的类,直接使用代理类完成原始类的功能,思路和设计也都比较简单。动态代理则是在运行时段,基于反射生成代理类的源码,主要用到了两个对象(Proxy和InvocationHandler接口),相对静态代理而言,代码编写上难度大一点,但是动态代理方式无需大量编写代理对象,如果原始类放生变动,静态代理则是比较奔溃的局面,代理类往往也需要改动,动态代理则相对改动较少。各有优缺点,建议可以在代理类比较少的情况下使用静态代理,其他情况使用动态代理,不确定情况也使用动态代理,多写两次就会写了。

学海无涯苦作舟!!!

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

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

相关文章

Versatile Diffusion—— 融合文本和图像的扩散模型

介绍 Diffusion模型在各种生成任务中取得了显著的进展&#xff0c;成为了一个重要的里程碑。特别是像DALLE 2、Imagen和Stable Diffusion&#xff08;SD&#xff09;这样的模型&#xff0c;不仅在学术界引起了广泛关注&#xff0c;也在工业界产生了深远影响。尽管这些模型在特…

10.Java对象内置结构

文章目录 Java对象内置结构1.Java对象的三个部分1.1.对象头1.2.对象体1.3.对齐字节 2.对象结构中核心字段的作用2.1.MarkWord(标记字)2.2.Class Pointer(类对象指针)2.3.Array Length(数组长度)2.4.对象体2.5.对齐字节 3.Mark Word的结构信息3.1.不同锁状态下的Mark Word字段结…

K邻算法:在风险传导中的创新应用与实践价值

程序员的实用神器 ⛳️ 写在前面参与规则&#xff01;&#xff01;&#xff01; ✅参与方式&#xff1a;关注博主、点赞、收藏、评论&#xff0c;任意评论&#xff08;每人最多评论三次&#xff09; ⛳️本次送书1~4本【取决于阅读量&#xff0c;阅读量越多&#xff0c;送的越…

Ubuntu24.04安装中文输入法

Ubuntu24.04安装中文输入法 为了更好的体验&#xff0c;请访问个人博客 www.huerpu.cc:7000 一、添加中文语言支持 在安装中文输入法之前&#xff0c;首选要添加中文语言支持。选择System&#xff0c;点击Region & Language。 点击Manage Install Languages。 点击Insta…

LED显示屏的维护与使用指南

LED显示屏作为一种先进的显示技术&#xff0c;广泛应用于广告、信息显示、舞台背景等领域。然而&#xff0c;为了确保显示屏的长期稳定运行和良好的显示效果&#xff0c;对其进行正确的维护和使用是非常必要的。以下是一些专业的维护与使用建议&#xff1a; 维护建议&#xff1…

Android iw 工具

代码位置:Android/external/iw 查看支持的命令: console:/ # iw help Usage: iw [options] command Options:--debug enable netlink debugging--version show version (4.1) Commands:help [command]Print usage for all or a specific command, e.g."…

六西格玛管理培训公司挑选攻略:如何找到最适合你的合作伙伴?

面对众多提供六西格玛管理培训的公司&#xff0c;企业如何挑选到真正适合自己的呢&#xff1f;本文有建议如下&#xff1a; 一、明确培训目标 在选择六西格玛管理培训公司之前&#xff0c;企业首先要明确自身的培训需求和目标。这包括确定培训的范围、期望达到的效果以及预算…

docker-compose完成mysql8.0+环境搭建

1、准备my.cnf文件到指定目录&#xff08;和基础的增加了一个default_authentication_pluginmysql_native_password 的身份验证插件配置信息&#xff09; 原因&#xff1a;官方提到&#xff1a; 该方式可以解决&#xff1a;Authentication plugin ‘caching_ sha2_password‘ c…

【代码分享】使用HTML5的Canvas绘制编码说明图片

最急在工作中遇到一个需求&#xff0c;根据给定的编码生成编码说明&#xff0c;像下面这样的效果。 不同含义的编码用横杠分割&#xff0c;然后每个编码下面用箭头指明具体的含义。下面是我使用canvas实现的代码。具体的编码宽度大家可以根据实际情况进行调整&#xff0c;目前…

炒股沪指放量涨逾1%,医药、酿酒等板块强势

5月首个交易日,两市股指高开高走,盘中大幅单边上行,两市成交额连续4个交易日突破万亿元,北向资金大举进场扫货,一度净买入超100亿元。 同创优配是AAA 级诚信经营示范单位,中国人民银行备案认证,天眼查可查询。是一家专注于股票投资、金融服务、及资产管理的专业机构 截至收盘…

代码随想录算法训练营第36期DAY14

DAY14&#xff08;周二&#xff09; 二叉树的递归遍历 144二叉树的前序遍历 过了。 /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullp…

简易的项目管理软件有哪些推荐?

简易的项目管理软件有很多&#xff0c;以下是一些推荐选项&#xff1a; zz-plan&#xff1a;https://zz-plan.com/ 作为一个在线甘特图工具&#xff0c;它适用于不同规模和复杂性的项目管理&#xff0c;能够轻松管理任务和进度。 Asana&#xff1a;https://asana.com/ 以其简…

4. FactoryTalk View SE按钮弹出二次确认

在按钮界面–按钮属性–添加释放动作–选择需要确认–配置–确定。 &#xff08;如果是用变量连接的比如需要输入密码等等选择使用变量&#xff09; 这样就完成了二次确认的窗口设置。

106短信群发平台:拓客拉新、商品促销,效果究竟如何?一试便知!

106短信群发平台在拓客拉新和商品促销方面的效果是非常显著的。 首先&#xff0c;从发送速度和到达率来看&#xff0c;106短信平台表现优秀。无论是节假日还是平日&#xff0c;其发送速度都能保持在一个较快的水平&#xff0c;这对于需要及时到达的营销信息尤为重要。同时&…

Leetcode—1991. 找到数组的中间位置【简单】

2024每日刷题&#xff08;129&#xff09; Leetcode—1991. 找到数组的中间位置 实现代码 class Solution { public:int findMiddleIndex(vector<int>& nums) {int sum accumulate(nums.begin(), nums.end(), 0);int prefix 0;for(int i 0; i < nums.size();…

第十三章 计算机网络

这里写目录标题 1.网络设备2.协议簇2.1电子邮件(传输层)2.2地址解析(网际层)2.3DHCP(动态主动配置协议)2.4URL(统一资源定位器)2.5IP地址和子网掩码 1.网络设备 物理层&#xff1a;中继器&#xff0c;集线器(多路中继器) 数据链路层&#xff1a;网桥&#xff0c;交换机(多端口…

软件FMEA的时机:架构设计、详设阶段——FMEA软件

免费试用FMEA软件-免费版-SunFMEA 软件FMEA&#xff08;故障模式与影响分析&#xff09;是一种预防性的质量工具&#xff0c;旨在识别软件中可能存在的故障模式&#xff0c;并分析其对系统性能、安全性和可靠性的影响。在软件开发生命周期中&#xff0c;选择适当的时机进行FME…

[Docker]容器的网络类型以及云计算

目录 知识梗概 1、常用命令2 2、容器的网络类型 3、云计算 4、云计算服务的几种主要模式 知识梗概 1、常用命令2 上一篇已经学了一些常用的命令&#xff0c;这里补充两个&#xff1a; 导出镜像文件&#xff1a;[rootdocker ~]# docker save -o nginx.tar nginx:laster 导…

rust调用SQLite实例

rusqlite库介绍 Rusqlite是一个用Rust编写的SQLite库&#xff0c;它提供了对SQLite数据库的操作功能。Rusqlite的设计目标是提供一个简洁易用的API&#xff0c;以便于Rust程序员能够方便地访问和操作SQLite数据库。 Rusqlite的主要特点包括&#xff1a; 遵循Rust的类型系统和…

用滑动条改变字体的大小(简单好抄)

1.首先在屏幕中添加一个滑动条和你要改变字体大小的文本&#xff08;用新版的&#xff09; 2.点击滑动条设置value的最大值和最小值 3.编写脚本 using System.ComponentModel; using TMPro; using UnityEngine; using UnityEngine.UI;public class FontSizeSlider : MonoBehav…