代理模式简介

概念

代理模式(Proxy Pattern)是一种结构型设计模式,它允许通过创建一个代理对象来控制对原始对象的访问。代理对象充当了客户端和目标对象之间的中介,可以在不改变目标对象的情况下增加额外的功能或限制访问。

特点

  1. 代理模式通过引入代理类来隐藏真实对象,并提供了与真实对象相同的接口,使得客户端无需直接与真实对象交互。
  2. 代理类可以在调用真实对象之前或之后执行额外的操作,如权限验证、缓存等。
  3. 客户端无法区分是否使用了代理,因为它们都遵循相同的接口。

优点

  1. 降低系统耦合度:将客户端和目标对象解耦,减少对目标类直接依赖。
  2. 提高安全性:通过代理进行权限验证和访问控制。
  3. 增强扩展性:可以在不修改源代码的情况下增加新功能。

缺点

  1. 增加复杂性:引入了额外的间接层,在一些简单场景下可能会增加代码复杂性。
  2. 对于某些涉及频繁调用的方法,由于需要经过多次转发导致性能降低。

适用场景

  1. 远程代理:用于在不同地址空间中访问对象,如远程方法调用(RPC)。
  2. 虚拟代理:用于按需加载大对象或延迟创建昂贵的对象,以提高系统性能。
  3. 安全代理:用于控制对敏感资源的访问权限。
  4. 智能引用代理:用于添加额外的操作,如缓存、日志记录等。

实现方式

静态代理

实现原理:

在编译时就已经确定了被代理类和具体的代理类,在代码中直接定义一个具体的实现类作为目标对象和一个对应的具体实现类作为代理对象。静态代理需要手动编写每个方法的转发逻辑,并且只能针对特定类型进行操作。

实现代码:

// 目标接口
interface Image {void display();
}// 目标类
class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadFromDisk();}private void loadFromDisk() {System.out.println("Loading image: " + filename);}@Overridepublic void display() {System.out.println("Displaying image: " + filename);}
}// 代理类
class ImageProxy implements Image {private String filename;private RealImage realImage;public ImageProxy(String filename) {this.filename = filename;this.realImage = null; // 初始时不加载真实对象}@Overridepublic void display() {if (realImage == null) { // 懒加载,只有在需要时才创建真实对象realImage = new RealImage(filename);}realImage.display();}
}public class Main {public static void main(String[] args) {Image image1 = new ImageProxy("image1.jpg");//无输出// 使用代理显示图片,只有在调用 `display()` 方法时才会加载真实图片对象image1.display();//输出 Loading image: image1.jpg//    Displaying image: image1.jpgImage image2 = new RealImage("image2.jpg");//输出Loading image: image2.jpg// 直接使用目标类显示图片,立即加载真实图片对象并显示image2.display();//输出 Displaying image: image2.jpg}
}

 在上述示例中,我们定义了一个目标接口 Image 和其具体实现类 RealImage。然后创建了一个代理类 ImagProxy来控制对目标对象的访问。当客户端创建代理类对象并不会马上加载图片,只有在调用display()时才会加载图片并展示图片。在创建目标对象时,会立刻加载图片。

动态代理:

动态代理是指在运行时动态生成代理类的过程,它不需要手动编写具体的代理类,而是通过 Java 的反射机制和字节码生成技术,在内存中创建一个新的代理类,并在运行时将方法调用转发给真实对象。

实现原理:

  1. 定义目标接口:首先需要定义一个目标接口,即被代理对象所遵循的接口。
  2. 实现 InvocationHandler 接口:创建一个实现 java.lang.reflect.InvocationHandler 接口的类,该类负责处理所有方法调用并执行相应操作。
  3. 创建 Proxy 对象:使用 java.lang.reflect.Proxy 类的静态方法 newProxyInstance() 来创建代理对象。此方法会返回一个实现了目标接口并由指定 InvocationHandler 处理方法调用的新对象。

实现代码:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 目标接口
interface Image {void display();
}// 目标类
class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadFromDisk();}private void loadFromDisk() {System.out.println("Loading image: " + filename);}@Overridepublic void display() {System.out.println("Displaying image: " + filename);}
}// InvocationHandler 实现类
class ImageInvocationHandler implements InvocationHandler {private Object target;public ImageInvocationHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 在方法调用前后可以执行一些额外操作,如权限验证、日志记录等System.out.println("Before method invocation");Object result = method.invoke(target, args);System.out.println("After method invocation");return result;}
}public class Main {public static void main(String[] args) {RealImage realImage = new RealImage("image.jpg");// 创建代理对象并绑定目标对象和 InvocationHandler 对象Image proxyImage = (Image) Proxy.newProxyInstance(realImage.getClass().getClassLoader(),realImage.getClass().getInterfaces(),new ImageInvocationHandler(realImage));// 通过代理对象调用方法,实际上会转发给真实对象的相应方法,并在前后执行额外操作proxyImage.display();}
}

在上述示例中,我们定义了一个目标接口 Image 和其具体实现类 RealImage。然后创建了一个实现了 java.lang.reflect.InvocationHandler 接口的类 ImagInvocatioHandler来处理所有方法调用。最后使用 java.lang.reflect.Proxy 类的静态方法 newProxInstance() 来创建代理对象,并将目标对象和 InvocationHandler 对象绑定在一起。当客户端通过代理对象调用方法时,实际上会转发给真实对象的相应方法,并在前后执行额外操作。使用了 Java 的反射机制和字节码生成技术,在运行时动态地创建代理类。

存在问题:

  1. 动态代理只能针对接口进行操作,无法直接对普通类进行操作。
  2. 由于每次都要通过反射来处理方法调用,因此性能上可能会有一些损耗。

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

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

相关文章

wx:for 微信小程序双重for嵌套如何获取内层的迭代对象

wx:for 微信小程序双重for嵌套如何获取内层的迭代对象 思路就是&#xff0c;外层for直接通过默认的item进行迭代&#xff0c;然后内层的for&#xff0c;通过wx:for-item"xxx"的方式指定内部迭代名称。 <view wx:for"{{modulesList}}" ><text>{…

【操作系统】电脑上没有IIS怎么办

文章目录 前言一、查看二、解决 前言 有的新机刚开始在计算机-管理-服务下没有IIS网络服务怎么办。 一、查看 桌面计算机/此电脑 鼠标右键&#xff1a;管理 服务和应用 发现没有IIS 二、解决 控制面板 程序和功能 启动或关闭Windows功能 IIS相关的所有功能选中&#xff…

鼠标键盘自动化工具pyautogui

安装 pip install pyautogui pip install keyboard获取鼠标实时位置 import pyautogui pyautogui.displayMousePosition()样例代码 # https://pyautogui.readthedocs.org/ # https://github.com/asweigart/pyautogui# 紧急停止&#xff0c;手动将鼠标移动到屏幕的4个角落imp…

2023年9月8日

1> 自行封装一个栈的类&#xff0c;包含私有成员属性&#xff1a;栈的数组、记录栈顶的变量 成员函数完成&#xff1a;构造函数、析构函数、拷贝构造函数、入栈、出栈、清空栈、判空、判满、获取栈顶元素、求栈的大小 #include <iostream>using namespace std;class…

selenium的Chrome116版驱动下载

这里写自定义目录标题 下载地址https://googlechromelabs.github.io/chrome-for-testing/#stable 选择chromedriver 对应的平台和版本 国内下载地址 https://download.csdn.net/download/dongtest/88314387

hive 分隔符

在 Hive 中,分隔符用于指定数据文件中字段之间的分隔符。当你创建外部表或加载数据文件时,你可以指定分隔符,以便 Hive 正确地解析文件中的数据。 1. 创建外部表时指定分隔符: 当你创建外部表时,可以使用 ROW FORMAT 子句来指定数据文件中字段的分隔符。例如,如果你的数…

WorkPlus AI助理,基于ChatGPT的企业级知识问答机器人

随着人工智能技术的发展&#xff0c;WorkPlus AI助理以ChatGPT对话能力为基础&#xff0c;将企业数据与人工智能相结合&#xff0c;推出了面向企业的知识问答机器人。这一创新性的解决方案帮助企业高效管理和利用自身的知识资产&#xff0c;助力企业级人工智能的构建。与传统的…

【MySQL】数据库的约束

MySQL 数据库的约束 文章目录 MySQL 数据库的约束01 数据库的约束1.1 约束类型1.1.1 NOT NULL1.1.2 UNIQUE1.1.3 DEFAULT1.1.4 PRIMARY KEY1.1.5 FOREIGN KEY1.1.6 CHECK 继上文 MySQL基础&#xff08;一&#xff09;&#xff0c; MySQL基础&#xff08;二&#xff09;&#…

介绍串行和并行两种通信方式

前言 参考文章&#xff1a; 串行和并行- CSDN搜索 并行传输和串行传输的区别_金陵大掌柜的博客-CSDN博客 串行和并行介绍 &#xff08;1&#xff09;串行和并行是计算机领域中两个重要的概念。串行是指在计算机中&#xff0c;任务按照顺序一个一个执行&#xff0c;每个任务执行…

详解初阶数据结构之顺序表(SeqList)——单文件文件实现SeqList的增删查改

目录 一、线性表 二、顺序表 2.1概念及结构 2.2接口实现 2.3动态顺序表的创建 2.3动态顺序表的初始化 2.3.1传值初始化 2.3.2传址初始化 2.4动态顺序表的清空 2.5动态顺序表的扩容 2.6动态顺序表内容的打印 三、动态顺序表的使用 3.1尾插尾删 3.1.1尾插 3.1.2尾删…

基于Bert+Attention+LSTM智能校园知识图谱问答推荐系统——NLP自然语言处理算法应用(含Python全部工程源码及训练模型)+数据集

目录 前言总体设计系统整体结构图系统流程图 运行环境Python 环境服务器环境 模块实现1. 构造数据集2. 识别网络3. 命名实体纠错4. 检索问题类别5. 查询结果 系统测试1. 命名实体识别网络测试2. 知识图谱问答系统整体测试 工程源代码下载其它资料下载 前言 这个项目充分利用了…

linux编辑器-vim

1.vim是什么 vim 是从 vi 发展出来的一个文本编辑器。代码补全、编译及错误跳转等方便编程的功能特别丰富&#xff0c;在程序员中被广泛使用。简单的来说&#xff0c; vi 是老式的字处理器&#xff0c;不过功能已经很齐全了&#xff0c;但是还是有可以进步的地方。 vim 则可以…

前端uniapp块样式写法

<template><view class"block"><view class"block_box"><view class"block_box_content"><view class"block_box_left">左边</view><view class"block_box_right">右边</view…

线性代数的学习和整理22:矩阵的点乘(草稿)

4 矩阵乘法 A,B两个同阶同秩N阵&#xff0c;看上去结构一样&#xff0c;但两厢相乘&#xff0c;在做在右&#xff0c;地位差别巨大。 在左&#xff0c;你就是基&#xff0c;是空间的根本&#xff0c;是坐标系&#xff0c;是往哪去、能到哪的定海神针&#xff0c;是如来佛手&a…

华为云云耀云服务器L实例评测|华为云云耀云服务器L实例评测使用

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

Kotlin学习记录

Kotlin学习记录 1. 权限修饰符1.1 internal 修饰符1.2 open 修饰符 2 其它修饰符2.1 lateinit 修饰符2.2 inline 修饰符2.3 var 修饰符 (变量)2.4 val 修饰符 (常量)2.5 typealias 3 申明对象3.1 申明对象不赋值3.2 申明对象并实例化3.3 申明常量并用 by lazy 懒加载 4 类、接口…

day-45 代码随想录算法训练营(19)动态规划 part 07

70.爬楼梯&#xff08;进阶&#xff09; 分析&#xff1a;基本动态规划转换为完全背包&#xff0c;因为1、2 两种上楼梯方式是无限选择的 思路&#xff1a; 1. j 表示 容量为 j 时&#xff0c;装满有dp[j]种方法2. dp[j]dp[j-nums[i]]3. 初始化 dp[0]1,dp[1]14. 遍历顺序&am…

[docker]笔记-portainer的安装

1、portainer是一款可视化的容器管理软件&#xff0c;利用portainer可以轻松方便的管理和创建容器。portainer本身是一个容器&#xff0c;完全免费并且具有汉化版。本文介绍portainer的安装和使用。 2、安装好容器并配置好容器环境&#xff0c;可参照https://blog.csdn.net/bl…

智安网络|面临日益增长的安全威胁:云安全和零信任架构的重要性

随着云计算技术的快速发展和广泛应用&#xff0c;云安全和零信任架构变得愈发重要。在数字化时代&#xff0c;云计算技术得到了广泛的应用和推广。企业和组织借助云服务提供商的强大能力&#xff0c;实现了高效、灵活和可扩展的IT基础设施。然而&#xff0c;随着云环境的快速发…

解决VSCode调试或者发布运行时闪退问题

解决方案&#xff1a;此方案不一定适合所有类型的闪退&#xff0c;但可以尝试一下。 步骤1&#xff1a;依次选择&#xff1a;文件→首选项→设置 步骤2&#xff1a;搜索 terminal.integrated.Default →找到Terminal > Integrated Default Profile: Windows选项→下拉框的…