当前位置: 首页 > article >正文

【设计模式-3.4】结构型——代理模式

说明:说明:本文介绍结构型设计模式之一的代理模式

定义

代理模式(Proxy Pattern)指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型设计模式。(引自《设计模式就该这样学》P158)

生活中有许多代理模式的应用,比如明星开演唱会、拍电影时,拉赞助、找场地、找投资这些事情,都不会自己亲自去做,都会有自己的经纪人、经纪公司去具体执行,这样经纪公司就控制了对明星的访问;又比如,工地工人,具有扛沙包、搬砖等能力,他们不会直接找工地老板沟通,而是委托给包工头,让包工头去和工地老板商量,包工头控制了对工地工人的访问。

影星与经纪人

以影星与经纪人为例,如下,是一个影星对象,具有属性名字,唱歌、拍电影方法

/*** 影星*/
public class MovieStar {/*** 名字*/private String name;public MovieStar(String name) {this.name = name;}/*** 唱歌** @param singName 歌名* @return 感谢语*/public String sing(String singName) {System.out.println(name + "在唱" + singName);return "谢谢大家!谢谢大家!";}/*** 拍电影** @param movieName 片名*/public void movie(String movieName) {System.out.println(name + "在拍" + movieName);}
}

经纪人代理了影星对象,如下:

/*** 影星经纪人*/
public class StarProxy {/*** 影星对象*/private MovieStar movieStar;/*** 构造器注入* @param name 影星名称*/public StarProxy(String name) {this.movieStar = new MovieStar(name);}/*** 代理唱歌** @param singName 歌名* @return 感谢*/public String sing(String singName) {System.out.println("经纪人在找场地");return movieStar.sing(singName);}/*** 代理拍电影** @param movieName 片名*/public void movie(String movieName) {System.out.println("经纪人在联系剧组");movieStar.movie(movieName);}
}

使用,如下:

public class Client {public static void main(String[] args) {StarProxy bigStar = new StarProxy("大明星");System.out.println(bigStar.sing("忘情水"));System.out.println("----------------------");bigStar.movie("《无间道》");}
}

运行如下,经纪人对象代理了影星对象

在这里插入图片描述

改进

以上代码,可将影星、经纪人对象的方法抽出来成接口,让他们都实现这个接口,可统一方法列表,如下:

(Star,明星接口)

/*** 明星接口*/
public interface Star {/*** 唱歌能力** @param singName 歌名* @return 感谢*/String sing(String singName);/*** 拍戏能力** @param movieName 片名*/void movie(String movieName);
}

(MovieStar,影星对象)

/*** 影星*/
public class MovieStar implements Star {/*** 名字*/private String name;public MovieStar(String name) {this.name = name;}/*** 唱歌** @param singName 歌名* @return*/@Overridepublic String sing(String singName) {System.out.println(name + "在唱" + singName);return "谢谢大家!谢谢大家!";}/*** 拍电影** @param movieName 片名*/@Overridepublic void movie(String movieName) {System.out.println(name + "在拍" + movieName);}
}

(StarProxy,影星代理)

/*** 影星代理*/
public class StarProxy implements Star {/*** 影星对象*/private MovieStar movieStar;/*** 构造器注入* @param name 影星名称*/public StarProxy(String name) {this.movieStar = new MovieStar(name);}/*** 代理唱歌** @param singName 歌名* @return 感谢*/@Overridepublic String sing(String singName) {System.out.println("代理人在找场地");return movieStar.sing(singName);}/*** 代理拍电影** @param movieName 片名*/@Overridepublic void movie(String movieName) {System.out.println("代理人在联系剧组");movieStar.movie(movieName);}
}

动态代理

以上手动实现代理的方式称为静态代理,在JDK中有提供动态代理,可以不用额外创建一个代理人对象,直接实现代理,如下:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class DynamicProxy {public static void main(String[] args) {// 1.创建影星对象MovieStar ldh = new MovieStar("刘德华");// 2.动态创建代理/*** Proxy.newProxyInstance()参数说明:* 参数一:类加载器,要使用和被代理对象相同的类加载器* 参数二:代理对象和被代理对象实现相同接口* 参数三:增强逻辑。通常使用匿名内部类编写逻辑*/Star proxy = (Star) Proxy.newProxyInstance(ldh.getClass().getClassLoader(),new Class[]{Star.class},new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {// 针对对象不同方法设置不同的附加操作if ("sing".equals(method.getName())) {System.out.println("代理人在找场地");} else if ("movie".equals(method.getName())) {System.out.println("代理人在联系剧组");}// 接收方法返回值,不用考虑方法无返回值的情况,是一种书写模式Object returnValue = method.invoke(ldh, args);// 返回方法的返回值return returnValue;}});// 3.执行代理人的方法,实际是影星对象在执行System.out.println(proxy.sing("忘情水"));System.out.println("----------------------");proxy.movie("无间道");}
}

可用lambda表达式简化代码,如下:

import java.lang.reflect.Proxy;public class DynamicProxy {public static void main(String[] args) {// 1.创建影星对象MovieStar ldh = new MovieStar("刘德华");// 2.动态创建代理/*** Proxy.newProxyInstance()参数说明:* 参数一:类加载器,要使用和被代理对象相同的类加载器* 参数二:代理对象和被代理对象实现相同接口* 参数三:增强逻辑。通常使用匿名内部类编写逻辑*/Star proxy = (Star) Proxy.newProxyInstance(ldh.getClass().getClassLoader(),new Class[]{Star.class},(proxy1, method, args1) -> {// 针对对象不同方法设置不同的附加操作if ("sing".equals(method.getName())) {System.out.println("代理人在找场地");} else if ("movie".equals(method.getName())) {System.out.println("代理人在联系剧组");}// 接收方法返回值,不用考虑方法无返回值的情况,是一种书写模式Object returnValue = method.invoke(ldh, args1);// 返回方法的返回值return returnValue;});// 3.执行代理人的方法,实际是影星对象在执行System.out.println(proxy.sing("忘情水"));System.out.println("----------------------");proxy.movie("无间道");}
}

执行如下,可见代理实现

在这里插入图片描述


动态代理是基于反射实现的,反射是通过解析对象的字节码(class)文件,反向实例化对象的技术。详细可参考下面这篇文章,了解了反射技术,我们完全可以自己手动实现一个对象的动态代理。

  • 反射技术

使用场景

代理模式的这种思想,我认为在实际开发中很常见。例如,为了避免频繁访问数据库,我们会将之前查询过的数据(例如根据主键查询某个用户的数据)存入到缓存中,下次当我们再次查询时,调用对应的Service方法,可以在查询数据库之前先去缓存中查一遍,缓存中没有,再去查数据库,这样可以减少查询数据库的频率。这就是代理思想的一种体现。


再例如,有一个面试题,如何解决ArrayList线程不安全的问题,其中的两个答案如下:

(1)定义一个MyArrayList类,继承ArrayList,重写其方法,每个方法用synchronized修饰;

(2)定义一个MyArrayList类,类里实例化一个ArrayList,自定义List的增删改查方法,用synchronized修饰,方法里调用ArrayList对应的方法;

以上两个方法,都是手动创建一个“代理对象”,以控制对对象内ArrayList的访问,也是代理思想的体现。


另外,还有强大的AOP,面向接口编程,也是代理的一种应用。

  • AOP技术

  • 使用AOP处理参数

  • 使用AOP记录请求日志实现

总结

本文介绍了结构型设计模式中的代理模式,参考《设计模式就该这样学》、《秒懂设计模式》两书。

相关文章:

【设计模式-3.4】结构型——代理模式

说明:说明:本文介绍结构型设计模式之一的代理模式 定义 代理模式(Proxy Pattern)指为其他对象提供一种代理,以控制对这个对象的访问,属于结构型设计模式。(引自《设计模式就该这样学》P158&am…...

电脑频繁黑屏怎么办

有没有遇到过这种糟心事儿:正兴致勃勃地打游戏、赶方案,或者追着喜欢的剧,电脑突然黑屏了!而且还频繁出现,简直让人抓狂。今天咱们就来好好聊聊,电脑频繁黑屏到底该怎么办。 硬件问题排查 检查显示器连接…...

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Sound Board(音响控制面板)

📅 我们继续 50 个小项目挑战!—— SoundBoard 组件 仓库地址:https://github.com/SunACong/50-vue-projects 项目预览地址:https://50-vue-projects.vercel.app/ 🎯 组件目标 实现一个响应式按钮面板,点…...

关于大数据的基础知识(一)——定义特征结构要素

成长路上不孤单😊😊😊😊😊😊 【14后😊///计算机爱好者😊///持续分享所学😊///如有需要欢迎收藏转发///😊】 今日分享关于大数据的基础知识(一&a…...

chrome使用手机调试触屏web

chrome://inspect/#devices 1、手机开启调试模式、打开usb调试 2、手机谷歌浏览器打开网站 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f1ef2d2c017c477ba55a57338ae13fc8.jpeg#pic_center 使用谷歌浏览器打开chrome://inspect/#devices 刷新浏览器点击inspect…...

浅谈量子计算:从实验室突破到产业落地的中国实践

引言:量子霸权争夺战的中国坐标 2025年5月30日,中国量子科技梦之队再次刷新世界纪录——潘建伟院士团队在量子京沪干线完成全球首个跨省量子密钥分发实验,成功实现北京金融数据中心与上海政务云平台间的绝对安全通信。这标志着我国在量子通信…...

68道Hbase高频题整理(附答案背诵版)

简述什么是Hbase数据库? Hbase是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,它利用HBase技术在HDFS上提供了类似于Bigtable的能力。换句话说,Hbase是Apache Hadoop生态系统中的一部分,可以为大数据应用提供快速的随机…...

python版若依框架开发:项目结构解析

python版若依框架开发 从0起步,扬帆起航。 python版若依部署代码生成指南,迅速落地CURD!项目结构解析 文章目录 python版若依框架开发前端后端 前端 后端...

国产linux系统(银河麒麟,统信uos)使用 PageOffice在线编辑word文件保存数据同时保存文件

在实际应用中,例如在线签订合同的时候,合同的签订日期,合同号等等这些信息既要保存到数据库,合同签订后又要将整个合同文件保存起来。这时候就需要用到PageOffice的保存数据区域数据的同时保存整个文件的功能。 后端代码 后端打…...

day34- 系统编程之 网络编程(TCP)

一、补充 ip地址:除了本机地址如:192.168.0.151还可以使用(自己测试)本地回环地址(127.0.0.1)或者使用htonl(INADDR_ANY); 二、模式 C/S 模式 ->服务器/客户端模型:TCP传输控制协议 2.1 …...

鸿蒙jsonToArkTS_工具exe版本来了

前言导读 相信大家在学习鸿蒙开发过程中最痛苦的就是编写model 类 特别是那种复杂的json的时候对不对, 这时候有一个自动化的工具给你生成model是不是很开心。我们今天要分享的就是这个工具 JsonToArkTs 的用法 工具地址 https://gitee.com/qiuyu123/jsontomodel…...

DeviceNet转Modbus TCP网关的远程遥控接收端连接研究

在港口码头作业中,遥控器因其精确的操作控制和稳定的性能,已成为起重机货物装卸作业的重要辅助工具。然而,在某港口码头实施无线遥控器远程控制掘进机的过程中,由于通信协议的不兼容,遭遇了技术难题。具体而言&#xf…...

ASP.NET Core 中间件深度解析:构建灵活高效的请求处理管道

在现代Web应用开发中,请求处理管道的设计和实现至关重要。ASP.NET Core通过其中间件(Middleware)系统提供了一种高度灵活、可扩展的方式来构建请求处理管道。本文将全面深入地探讨ASP.NET Core中间件的概念、工作原理、实现方式以及最佳实践,帮助开发者掌…...

开关机、重启、改密、登录:图解腾讯云CVM日常管理核心操作,轻松掌控你的云主机

更多服务器知识,尽在hostol.com 嘿,各位腾讯云的“新晋地主”们!恭喜你成功“开垦”了自己的第一片“云端沃土”——拥有了一台崭新的云服务器CVM!现在,这台CVM就像一部功能强大的超级智能电视,已经送到你…...

从0到1认识ElasticStack

一、ES集群部署 操作系统Ubuntu22.04LTS/主机名IP地址主机配置elk9110.0.0.91/244Core8GB100GB磁盘elk9210.0.0.92/244Core8GB100GB磁盘elk9310.0.0.93/244Core8GB100GB磁盘 1. 什么是ElasticStack? # 官网 https://www.elastic.co/ ElasticStack早期名称为elk。 elk分别…...

I2C 外设知识体系:从基础到 STM32 硬件实现

文章目录 I2C外设简介I2C 通信实现方式对比1. 软件模拟 I2C2. 硬件实现 I2C STM32 I2C 外设核心功能1. 硬件特性2. 寄存器与引脚 I2C框图一、引脚接口二、数据处理模块三、时钟控制模块四、控制逻辑模块五、辅助功能 I2C基本结构主机发送一、7 位主发送序列二、10 位主发送序列…...

vue和uniapp聊天页面右侧滚动条自动到底部

1.vue右侧滚动条自动到底部 <div ref"newMessage1"></div> <!-- 定义<div ref"newMessage1"></div>与<div v-for”item in list“>循环同级定义-->定义方法 scrollToBottomCenter(){this.$nextTick(() > {this.$re…...

文件索引:数组、二叉树、二叉排序树、平衡树、红黑树、B树、B+树

参考链接&#xff1a;https://www.bilibili.com/video/BV1mY4y1W7pS 数据结构可视化工具&#xff1a;https://www.cs.usfca.edu/~galles/visualization/Algorithms.html 问题引出&#xff1a;一般是什么原因导致从磁盘查找数据效率低&#xff1f; 通过索引来更快的查询数据&a…...

PHP的namespace

文章目录 环境Java的packagepackage关键字包结构和目录结构访问权限import关键字总结 PHP的namespacenamespace关键字在同一个文件里使用资源限定&#xff0c;完全限定&#xff0c;非限定限定完全限定非限定 use关键字use VS 直接指定资源在不同的文件里使用总结 环境 Windows…...

《仿盒马》app开发技术分享-- 商品搜索页(顶部搜索bar热门搜索)(端云一体)

开发准备 随着开发功能的逐渐深入&#xff0c;我们的应用逐渐趋于完善&#xff0c;现在我们需要继续在首页给没有使用按钮以及组件添加对应的功能&#xff0c;这一节我们要实现的功能是商品搜索页面&#xff0c;这个页面我们从上到下开始实现功能&#xff0c;首先就是一个搜索…...

10_聚类

描述 聚类&#xff08;clustering&#xff09;是将数据集划分成组的任务&#xff0c;这些组叫作簇&#xff08;cluster&#xff09;。其目标是划分数据&#xff0c;使得一个簇内的数据点非常相似且不同簇内的数据点非常不同。与分类算法类似&#xff0c;聚类算法为每个数据点分…...

网络安全:网页密码防护与记住密码功能的安全

引言 在数字化时代&#xff0c;网页应用已成为人们生活和工作中不可或缺的一部分。用户登录作为网页应用的第一道防线&#xff0c;其密码防护机制至关重要。而 “记住密码” 功能虽然极大提升了用户体验&#xff0c;但也带来了诸多安全风险。从密码存储漏洞导致的数据泄露&…...

Tensorborad

一、tensorboard的基本操作 1.1 发展历史 TensorBoard 是 TensorFlow 生态中的官方可视化工具&#xff08;也可无缝集成 PyTorch&#xff09;&#xff0c;用于实时监控训练过程、可视化模型结构、分析数据分布、对比实验结果等。它通过网页端交互界面&#xff0c;将枯燥的训练…...

Kafka存储机制核心优势剖析

文章目录 Kafka存储机制核心优势剖析1. **写入路径:Page Cache vs. 应用层缓存**2. **Page Cache工作原理解析**3. **顺序写盘 vs. 随机写盘**4. **资源利用最优化****为什么Page Cache方案更优?**1. **双缓存问题彻底解决**2. **读写路径统一优化**3. **故障恢复优势****生产…...

day027-Shell自动化编程-基础

文章目录 1. 修改vim配置文件自动添加注释2. 故障案例&#xff1a;Windows上写的Shell脚本上传到Linux系统上运行报错3. 脚本运行方法4. 变量4.1 普通变量4.2 环境变量4.3 特殊变量4.4 案例&#xff1a;书写ping检查脚本&#xff0c;检查脚本传入的第一个参数4.5 面试题&#x…...

工业自动化DeviceNET从站转Ethernet/IP主站网关赋能冶金行业工业机器人高效运行

在冶金行业高速发展的当下&#xff0c;对生产效率与精度的要求不断攀升。工业机器人凭借其精准、高效的特性&#xff0c;在钻孔、铣削、切割、弯曲、冲压等加工工艺中广泛应用。然而&#xff0c;不同设备间的通信协议差异常成为制约系统协同的瓶颈。JH-DVN-EIP疆鸿智能DeviceNE…...

STM32启动文件学习(startup_stm32f40xx.s)

原代码 ;******************** (C) COPYRIGHT 2016 STMicroelectronics ******************** ;* File Name : startup_stm32f40xx.s ;* Author : MCD Application Team ;* version : V1.8.0 ;* date : 09-November-2016 ;* Desc…...

构建高效可靠的电商 API:设计原则与实践指南

引言 在数字化浪潮中&#xff0c;电商 API 接口技术已成为连接不同系统、实现数据高效流通的核心桥梁。通过标准化的协议和工具集合&#xff0c;API 不仅支撑了商品管理、订单处理等基础功能&#xff0c;还为个性化推荐、全球供应链协同等创新场景提供了底层支持。本文将结合行…...

开源数据库MySQL 与 PostgreSQL的巅峰对决。

MySQL 与 PostgreSQL 是两大主流开源关系型数据库&#xff0c;其核心差异主要体现在架构设计、功能特性、性能优化及适用场景上。结合最新技术对比和行业实践&#xff0c;以下为深度解析&#xff1a; &#x1f9e0; ​​一、架构与设计哲学​​ ​​维度​​​​PostgreSQL​​…...

从 LeetCode 到日志匹配:一行 Swift 实现规则识别

文章目录 摘要描述题解答案题解代码分析示例测试及结果时间复杂度空间复杂度总结 摘要 在开发中我们经常遇到“模式匹配”的问题&#xff0c;比如日志分类、用户意图识别、甚至是在一些权限系统中做规则映射判断。这类问题的本质是判断两个结构是否具有一致的对应关系。LeetCo…...