详解设计模式:代理模式

news2024/10/6 20:34:48

代理模式(Proxy Pattern),Java 常见的设计模式之一,是 GoF 的 23 种设计模式中的一种结构型设计模式。

代理模式 是指客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。代理对象 具备真实对象的功能,并代替真实对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理(为真实对象提供代理,然后供其他对象通过代理访问真实对象)。

~

本篇内容包括:关于代理模式、代理(静态代理)实现 Demo、代理(动态代理)实现 Demo、代理(CGLIB 动态代理)实现 Demo


文章目录

    • 一、关于代理模式
        • 1、关于代理模式
        • 2、关于代理模式的构成
        • 3、关于代理模式的XML
        • 4、关于代理模式的应用场景
        • 5、关于代理模式的优缺点
    • 二、代理(静态代理)实现 Demo
        • 1、Demo 实现
        • 2、Demo 测试
    • 三、代理(动态代理)实现 Demo
        • 1、动态代理
        • 2、Demo 实现
        • 3、Demo 测试
    • 四、代理(CGLIB 动态代理)实现 Demo
        • 1、CGLIB 动态代理
        • 2、Maven 坐标
        • 3、Demo 实现
        • 4、Demo 测试


一、关于代理模式

1、关于代理模式

代理模式(Proxy Pattern),Java 常见的设计模式之一,是 GoF 的 23 种设计模式中的一种结构型设计模式。

代理模式 是指客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。代理对象 具备真实对象的功能,并代替真实对象完成相应操作,并能够在操作执行的前后,对操作进行增强处理(为真实对象提供代理,然后供其他对象通过代理访问真实对象)。

Java 中的代理按照代理类生成时机不同又分为静态代理和动态代理。静态代理代理类在编译期就生成,而动态代理代理类则是在 Java 运行时动态生成。动态代理又有 JDK 代理和 CGLib 代理两种。

2、关于代理模式的构成

适配器模式一般包含三种角色:

  • 抽象主题角色(Subject):通过接口或抽象类声明真实角色实现的业务方法。
  • 代理主题角色(Proxy):实现抽象角色,是真实角色的代理(访问层),通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
  • 真实主题角色(RealSubject):实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

3、关于代理模式的XML

在这里插入图片描述

4、关于代理模式的应用场景

当无法或不想直接引用某个对象或访问某个对象存在困难时,可以通过代理对象来间接访问。使用代理模式主要有两个目的:一是保护目标对象,二是增强目标对象。

  • 远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。
  • 虚拟代理,这种方式通常用于要创建的目标对象开销很大时。例如,下载一幅很大的图像需要很长时间,因某种计算比较复杂而短时间无法完成,这时可以先用小比例的虚拟代理替换真实的对象,消除用户对服务器慢的感觉。
  • 安全代理,这种方式通常用于控制不同种类客户对真实对象的访问权限。
  • 智能指引,主要用于调用目标对象时,代理附加一些额外的处理功能。例如,增加计算真实对象的引用次数的功能,这样当该对象没有被引用时,就可以自动释放它。
  • 延迟加载,指为了提高系统的性能,延迟对目标的加载。例如,Hibernate 中就存在属性的延迟加载和关联表的延时加载。

5、关于代理模式的优缺点

# 代理模式的优点:

  • 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
  • 代理对象可以扩展目标对象的功能;
  • 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;

# 代理模式的缺点:

  • 代理模式会造成系统设计中类的数量增加(静态)
  • 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢(静态);
  • 增加了系统的复杂度

二、代理(静态代理)实现 Demo

1、Demo 实现

# Subject 抽象主题

interface Subject {
    void Request();
}

# RealSubject 真实主题

class RealSubject implements Subject {
    public void Request() {
        System.out.println("访问真实主题方法...");
    }
}

# Proxy 代理

class Proxy implements Subject {
    private RealSubject realSubject;
    public void Request() {
        if (realSubject == null) {
            realSubject = new RealSubject();
        }
        preRequest();
        realSubject.Request();
        postRequest();
    }
    public void preRequest() {
        System.out.println("访问真实主题之前的预处理。");
    }
    public void postRequest() {
        System.out.println("访问真实主题之后的后续处理。");
    }
}

2、Demo 测试

# 测试

public class Client {
    public static void main(String[] args) {
        Proxy proxy = new Proxy();
        proxy.Request();
    }
}

三、代理(动态代理)实现 Demo

1、动态代理

由于静态代理只能够对一种类型(接口)进行代理,如果想要对多种类型进行代理的话就需要创建多个代理类,为了弥补了静态代理的不足,从而出现了动态代理,使用反射技术实现

反射包 java.lang.reflect, 里面有三个类:InvocationHandler, Method, Proxy。

2、Demo 实现

# SellTickets 抽象主题

public interface SellTickets {
    void sell();
}

# TrainStation 真实主题

public class TrainStation implements SellTickets {

    public void sell() {
        System.out.println("火车站卖票");
    }
}

# ProxyFactory 代理工厂,用来创建代理对象

public class ProxyFactory {

    private TrainStation station = new TrainStation();

    public SellTickets getProxyObject() {
        //使用Proxy获取代理对象
        /*
            newProxyInstance()方法参数说明:
                ClassLoader loader : 类加载器,用于加载代理类,使用真实对象的类加载器即可
                Class<?>[] interfaces : 真实对象所实现的接口,代理模式真实对象和代理对象实现相同的接口
                InvocationHandler h : 代理对象的调用处理程序
         */
        SellTickets sellTickets = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),
                station.getClass().getInterfaces(),
                new InvocationHandler() {
                    /*
                        InvocationHandler中invoke方法参数说明:
                            proxy : 代理对象
                            method : 对应于在代理对象上调用的接口方法的 Method 实例
                            args : 代理对象调用接口方法时传递的实际参数
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        System.out.println("代理点收取一些服务费用(JDK动态代理方式)");
                        //执行真实对象
                        Object result = method.invoke(station, args);
                        return result;
                    }
                });
        return sellTickets;
    }
}

3、Demo 测试

# 测试

public class Client {
    public static void main(String[] args) {
        //获取代理对象
        ProxyFactory factory = new ProxyFactory();
        
        SellTickets proxyObject = factory.getProxyObject();
        proxyObject.sell();
    }
}

四、代理(CGLIB 动态代理)实现 Demo

1、CGLIB 动态代理

同样是上面的案例,我们再次使用 CGLIB 代理实现。

如果没有定义 SellTickets 接口,只定义了 TrainStation(火车站类)。很显然 JDK 代理是无法使用了,因为 JDK 动态代理要求必须定义接口,对接口进行代理。

CGLIB 是一个功能强大,高性能的代码生成包。它为没有实现接口的类提供代理,为 JDK 的动态代理提供了很好的补充。

2、Maven 坐标

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

3、Demo 实现

//火车站
public class TrainStation {

    public void sell() {
        System.out.println("火车站卖票");
    }
}

//代理工厂
public class ProxyFactory implements MethodInterceptor {

    private TrainStation target = new TrainStation();

    public TrainStation getProxyObject() {
        //创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
        Enhancer enhancer =new Enhancer();
        //设置父类的字节码对象
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        //创建代理对象
        TrainStation obj = (TrainStation) enhancer.create();
        return obj;
    }

    /*
        intercept方法参数说明:
            o : 代理对象
            method : 真实对象中的方法的Method实例
            args : 实际参数
            methodProxy :代理对象中的方法的method实例
     */
    public TrainStation intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("代理点收取一些服务费用(CGLIB动态代理方式)");
        TrainStation result = (TrainStation) methodProxy.invokeSuper(o, args);
        return result;
    }
}

4、Demo 测试

//测试类
public class Client {
    public static void main(String[] args) {
        //创建代理工厂对象
        ProxyFactory factory = new ProxyFactory();
        //获取代理对象
        TrainStation proxyObject = factory.getProxyObject();

        proxyObject.sell();
    }
}

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

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

相关文章

矢量三维电磁铁的技术参数

产品介绍&#xff1a; 锦正茂自主研发的多极电磁铁以四极电磁铁居多&#xff0c;也有五极、六极、八极等多极的应用&#xff0c;主要应用于多极磁环充磁、径向梯度磁场、旋转磁场磁导向等多种应用。 产品用途&#xff1a; 电磁铁/电磁场发生器主要用于磁滞现象研究、磁化系数测…

SAP-S4 BP 业务伙伴(客户与供应商)管理后台配置

目录 一、定义业务伙伴角色 二、客户和BP主数据同步配置 三 、激活对话中平台对象的PPo请求 四、勾选活动的同步选项 五、定义编码范围 ​编辑 六、 设置客户与供应商的编码范围 一、定义业务伙伴角色 业务伙伴 IMG路径 &#xff1a; 跨应用组件->SAP业务伙伴 -> …

热门Java开发工具IDEA入门指南——如何配置IDE

IntelliJ IDEA&#xff0c;是java编程语言开发的集成环境。IntelliJ在业界被公认为最好的java开发工具&#xff0c;尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(git、svn等)、JUnit、CVS整合、代码分析、 创新的GUI设计等方面的功能是非常强大的。 上文…

HarmonyOS应用API手势方法-PinchGesture

描述&#xff1a;用于触发捏合手势&#xff0c;触发捏合手势的最少手指为2指&#xff0c;最大为5指&#xff0c;最小识别距离为3vp。 Api&#xff1a;从API Version 7开始支持 接口&#xff1a;PinchGesture(value?: { fingers?: number, distance?: number }) 参数&…

【Android App】实战项目之仿微信的私信和群聊App(附源码和演示视频 超详细必看)

需要全部代码请点赞关注收藏后评论区留言私信~~~ 手机最开始用于通话&#xff0c;后来增加了短信功能&#xff0c;初步满足了人与人之间的沟通需求。然而短信只能发文字&#xff0c;于是出现了能够发图片的彩信&#xff0c;但不管短信还是彩信&#xff0c;资费都太贵了&#xf…

极光Q3财报解读:营收稳健控费见效 估值修复空间巨大

极光似乎正在渡过转型阵痛期。 11月23日&#xff0c;极光移动股份有限公司(JG.US)公布了2022年第三季度未经审计财务业绩&#xff0c;营收1130万美元&#xff0c;环比上升6%&#xff0c;同比降幅收窄&#xff0c;虽然低于市场预期的1214万美元&#xff0c;但是客户总数同比增长…

[Java反序列化]—CommonsCollections5

先贴张其他师傅的图 其实 CC5就是CC1的一种变形&#xff0c;前半段改修一下&#xff0c;后面接上就是CC5了。CC1是通过AnnotationInvocationHandler.invoke()获取get()&#xff0c;而CC5则是通过TiedMapEntry.toString()&#xff0c;其余部分都是一样的 分析 看看TiedMapEntr…

[附源码]Python计算机毕业设计Django-大学生健康档案管理

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Codeforces Round #836 (Div. 2) A.B.C.D

A. SSeeeeiinngg DDoouubbllee 题目链接&#xff1a; Problem - A - Codeforces 题面&#xff1a; 题意&#xff1a; 给定一个字符串&#xff0c;把这个字符串每个字符重复两遍后重新排序一定是一个回文串&#xff0c;问这个回文串是什么 思路&#xff1a; 题目是多种答案…

LVS-DR模式单网段和多网段案例实现

1 实验环境&#xff1a; 一台&#xff1a;客户端 eth0:仅主机 192.168.10.8/24 GW:192.168.10.18一台&#xff1a;ROUTER eth0 :NAT 192.168.100.18/24 eth1: 仅主机 192.168.10.18/24 启用 IP_FORWARD一台&#xff1a;LVS eth0:NAT:DIP:192.168.100.48/24 GW:192.168.100.18两…

进程与信号(三)

目录 一、前言 二、Signals 1、Signal Handling&#xff08;ctrlc.c&#xff09; 2、Sending Signals &#xff08;1&#xff09;alarm.c &#xff08;2&#xff09;A Robust Signals Interface &#xff08;3&#xff09;ctrlc2.c 3、Signal Sets &#xff08;1&…

小学生python游戏编程arcade----单词对错检测及记录写入excel中

小学生python游戏编程arcade----单词对错检测及记录写入excel中前言单词对错检测及记录写入excel中1、excel读取修改1.1 excel读取1.2 修改用到的库1.3 获取Excel表格名称的三种方式1.4 excel格式问题excel文件保存2.1 保存函数2.2 实验2.3 游戏中调用修改2.4 升级时保存字典内…

SuperMap GIS管线数据优化

一、优化目的 城市管网数据错综复杂&#xff0c;未经优化处理的数据在加载过程中可能会出现显示效果差&#xff0c;浏览效率低的情况&#xff0c;特别是在浏览器端&#xff0c;受文件请求量&#xff0c;网络带宽、硬件性能等方面的影响&#xff0c;未经优化的管线数据显示可能不…

5个高清图片素材网站,无水印,免费商用。

网上找的图片素材清晰度不够&#xff0c;版权不明确怎么办。看看这几个可商用图片素材网站&#xff0c;解决你的所有图片需求&#xff0c;高清无水印、下载无限制、免费可商用&#xff0c;赶紧马住&#xff01; 1、菜鸟图库 https://www.sucai999.com/pic.html?vNTYxMjky 网站…

【学习笔记54】运动函数的分析

一、运动函数的基本实现 运动函数是我们自己封装的一个函数。作用是将css样式的改变不是一次性完成&#xff0c;是逐步完成执行效果&#xff0c;看上去像是动画/运动完成的css样式改变。实际项目中框架等都有自己的运动函数我们目前封装一个简单的兼容多属性的运动函数。 1、HT…

回溯法(Java)

回溯法&#xff08;Java&#xff09; 文章目录回溯法&#xff08;Java&#xff09;1、引言2、回溯法2.1 定义2.2 使用场合2.3 基本做法2.4 具体做法2.5 常见例子3、比较4、 问题的解空间4.1 介绍4.2 解空间&#xff08;Solution Space&#xff09;4.3 举例5、基本思想5.1 基本步…

Starday跨境电商平台靠“三快”取胜

入驻快、支付快、物流快 在这个瞬息万变的互联网世界&#xff0c;追求“快”已经成为各行各业的共识&#xff0c;而对于一个因互联网发展而诞生的新兴行业——跨境电商行业&#xff0c;“快”就是跨境电商行业的第一生产力&#xff0c;要想在众多的跨境电商行业中成功出圈&…

【allegro 17.4软件操作保姆级教程六】布线操作基础之一

目录 1.1走线和修线 1.2 Copy操作 1.3 change操作 1.4 删除操作 1.5 Z-copy操作 1.6 Sub-drawing操作 1.1走线和修线 这两个操作是布线时用的最多最基础的操作。如下图&#xff0c;左边是走线命令&#xff08;add connect&#xff09;&#xff0c;右边是修线命令&#x…

外卖项目(项目优化3)12---前后端分离开发

目录 问题描述&#xff1a;184 一、前后端分离开发 185 1.1介绍 185 1.2开发流程 1.3前端技术栈 二、YAPI 186 2.1介绍 2.2使用方式 三、Swagger 187 3.1介绍 3.2使用方式&#xff08;步骤&#xff09; 3.3Swagger---常用注解 188 四、项目部署 189 4.1部署架构…

虹科分享 | 网络流量监控 | 使用 ntopng 收件人和端点进行灵活的警报处理

在之前&#xff0c;ntopng引擎对所有警报的配置是单一的&#xff1a;进入偏好页面并指定警报的发送地点。但这是不理想的&#xff0c;原因有很多&#xff1a;包括不可能在不同的渠道向不同的收件人发送警报&#xff0c;或有选择地决定何时发送警报。 出于这个原因&#xff0c;…