Java设计模式-代理模式

简介

代理模式是一种结构型设计模式,它可以让我们通过一个代理对象来访问一个真实的目标对象,从而实现对目标对象的功能扩展或保护。代理模式的主要角色有三个:

  • 抽象主题(Subject):定义了真实主题和代理主题的公共接口,使得在任何使用真实主题的地方都可以使用代理主题。
  • 真实主题(RealSubject):实现了抽象主题的接口,定义了真实的业务逻辑,是代理主题所代表的真实对象。
  • 代理主题(Proxy):也实现了抽象主题的接口,但是在调用真实主题的方法之前或之后,可以执行一些额外的操作,从而对真实主题进行控制或增强。

代理模式可以帮助我们解决以下几种问题:

  • 当我们无法或不想直接访问一个对象时,可以通过一个代理对象来间接访问,例如远程代理、虚拟代理等。
  • 当我们想要给一个对象提供额外的功能时,可以通过一个代理对象来实现,而不需要修改原有的对象,例如缓存代理、日志代理等。
  • 当我们想要给一个对象增加一些访问控制或安全保护时,可以通过一个代理对象来实现,例如防火墙代理、权限代理等。

实现

根据代理模式的定义,我们可以用以下的类图来表示它的结构:

image-20230505112244447

其中,Client是客户端类,它需要使用Subject接口提供的方法。Proxy是代理类,它持有一个RealSubject的引用,并且实现了Subject接口。RealSubject是真实类,它也实现了Subject接口,并且定义了具体的业务逻辑。

代理模式有多种类型,例如静态代理、动态代理等,代理模式也有自己的优缺点,使用时需要根据具体的场景和需求来选择合适的类型和方式。

静态代理实现

下面我们用Java代码来实现一个静态代理的例子:

// 抽象主题接口
public interface Subject {
    // 定义一个抽象方法
    void request();
}

// 真实主题类
public class RealSubject implements Subject {
    // 实现抽象方法
    @Override
    public void request() {
        // 真实的业务逻辑
        System.out.println("RealSubject is doing something...");
    }
}

// 代理主题类
public class Proxy implements Subject {
    // 持有一个真实主题的引用
    private RealSubject realSubject;

    // 构造方法,传入一个真实主题对象
    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    // 实现抽象方法
    @Override
    public void request() {
        // 在调用真实主题之前,可以执行一些额外操作
        System.out.println("Proxy is doing something before...");
        // 调用真实主题的方法
        realSubject.request();
        // 在调用真实主题之后,可以执行一些额外操作
        System.out.println("Proxy is doing something after...");
    }
}

// 客户端类
public class Client {
    public static void main(String[] args) {
        // 创建一个真实主题对象
        RealSubject realSubject = new RealSubject();
        // 创建一个代理对象,并传入真实主题对象
        Proxy proxy = new Proxy(realSubject);
        // 使用代理对象来调用抽象方法
	    proxy.request();
	}
}
运行结果如下:
Proxy is doing something before...
RealSubject is doing something...
Proxy is doing something after...

从运行结果可以看出,代理对象在调用真实对象的方法之前和之后,都执行了一些额外的操作,从而对真实对象进行了增强或控制。

动态代理实现

动态代理是一种特殊的代理模式,它可以在运行时动态地创建代理对象,而不需要事先定义代理类。动态代理可以更灵活地适应不同的场景和需求,但是也更复杂和难以理解。

这个例子是使用JDK动态代理来实现一个日志代理,它可以在调用目标对象的方法之前和之后,记录相关的日志信息。代码如下:

// 抽象主题接口
public interface Subject {
    // 定义一个抽象方法
    void request();
}

// 真实主题类
public class RealSubject implements Subject {
    // 实现抽象方法
    @Override
    public void request() {
        // 真实的业务逻辑
        System.out.println("RealSubject is doing something...");
    }
}

// 日志处理器类,实现了InvocationHandler接口,用于定义代理逻辑
public class LogHandler implements InvocationHandler {
    // 持有一个目标对象的引用
    private Object target;

    // 构造方法,传入一个目标对象
    public LogHandler(Object target) {
        this.target = target;
    }

    // 实现invoke方法,用于调用目标对象的方法,并在之前和之后执行日志操作
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在调用目标对象之前,记录开始时间
        long startTime = System.currentTimeMillis();
        System.out.println("开始执行" + method.getName() + "方法...");
        // 调用目标对象的方法,并获取返回值
        Object result = method.invoke(target, args);
        // 在调用目标对象之后,记录结束时间和耗时
        long endTime = System.currentTimeMillis();
        long duration = endTime - startTime;
        System.out.println("结束执行" + method.getName() + "方法,耗时" + duration + "毫秒");
        // 返回结果
        return result;
    }
}

// 客户端类
public class Client {
    public static void main(String[] args) {
        // 创建一个真实主题对象
        RealSubject realSubject = new RealSubject();
        // 创建一个日志处理器对象,并传入真实主题对象
        LogHandler logHandler = new LogHandler(realSubject);
        // 使用Proxy类的静态方法newProxyInstance来动态地创建一个代理对象,传入真实主题对象的类加载器、接口和处理器
        Subject proxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), logHandler);
        // 使用代理对象来调用抽象方法
        proxy.request();
    }
}

运行结果如下:

开始执行request方法...
RealSubject is doing something...
结束执行request方法,耗时1毫秒

从运行结果可以看出,代理对象在调用真实对象的方法之前和之后,都执行了一些日志操作,从而对真实对象进行了增强。

优缺点

静态代理模式

优点:

  • 代理模式可以实现对真实对象的功能扩展或保护,而不需要修改原有的对象,符合开闭原则。
  • 代理模式可以实现对真实对象的访问控制或延迟加载,提高系统的性能和安全性。
  • 代理模式可以实现对真实对象的透明访问,客户端只需要使用抽象主题的接口,而不需要关心真实对象和代理对象的细节。

缺点:

  • 代理模式会增加系统的复杂度和开销,因为需要创建和维护代理对象。
  • 代理模式可能会降低系统的响应速度,因为每次调用真实对象的方法都需要经过代理对象。

动态代理模式

优点:

  • 动态代理可以在运行时动态地创建代理对象,而不需要事先定义代理类,这样可以减少代码量和提高开发效率。
  • 动态代理可以根据不同的目标对象和需求,灵活地生成不同的代理对象,这样可以增加系统的可扩展性和可维护性。
  • 动态代理可以实现对目标对象的透明访问,客户端只需要使用抽象主题的接口,而不需要关心真实对象和代理对象的细节。

缺点:

  • 动态代理需要使用反射和字节码技术来生成代理对象,这样会增加系统的复杂度和开销,也可能会影响系统的性能和稳定性。
  • 动态代理需要遵循一些约束和限制,例如JDK动态代理只能代理实现了接口的类,CGLIB动态代理不能代理final类或方法等,这样会降低系统的灵活性和通用性。
  • 动态代理比静态代理更难以理解和掌握,需要有一定的基础知识和经验才能使用好动态代理。

运用场景

  • 当我们需要访问一个远程对象时,可以使用远程代理,它可以隐藏远程对象的位置和通信细节,让客户端像访问本地对象一样访问远程对象。
  • 当我们需要创建一个开销很大的对象时,可以使用虚拟代理,它可以在真正需要的时候才创建真实对象,从而实现延迟加载和节省资源。
  • 当我们需要给一个对象增加一些额外的功能时,可以使用装饰代理,它可以在不修改原有对象的情况下,给对象添加一些新的行为或属性。
  • 当我们需要给一个对象增加一些访问控制或安全保护时,可以使用保护代理,它可以根据不同的用户或角色,对对象的访问进行限制或检查。
  • 当我们需要给一个对象增加一些日志记录或性能监控时,可以使用日志代理或性能代理,它可以在调用对象的方法之前或之后,记录相关的信息或数据。

总结

代理模式是一种常用的结构型设计模式,它可以让我们通过一个代理对象来间接访问一个真实对象,从而实现对目标对象的功能扩展或保护。代理模式有三个主要角色:抽象主题、真实主题和代理主题。代理模式有多种类型,例如静态代理、动态代理、远程代理、虚拟代理等。代理模式有自己的优缺点,使用时需要根据具体的场景和需求来选择合适的类型和方式。

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

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

相关文章

【Mybatis】增删改查

1.添加相应的jar包 2.创建持久化类 在src目录下创建一个名为com.mybatis.po的包 创建持久化类MyUser,包含三个属性(uid,uname,usex) package com.mybatis.po; /***springtest数据库中user表的持久化类*/ public class MyUser {private Integer uid;//主键private…

OpenGL(六)——坐标系统

目录 一、前言 二、空间系 2.1 局部空间 2.2 世界空间 2.3 观察空间 2.4裁剪空间 2.5 正射投影 2.6 透视投影 2.7 屏幕空间 三、透视箱子 3.1 创建模型矩阵 3.2 创建观察矩阵 3.3 创建透视投影矩阵 3.4 修改顶点着色器 3.5 传递变换矩阵 四、旋转的箱子 五、好…

[Gitops--10]微服务项目部署流水线编写

微服务项目部署流水线编写 1. 部署环境说明 序号管理地址作用1192.168.31.199GitLab2192.168.31.104Harbor3192.168.31.131kubesphere 1.1 GitLab 1.2 流水线 1.2.1 创建流水线 1.2.2 创建凭证 1.2.3 创建kubeconfig凭证 这里需要注意的是,config中如果使用的是域名,那么需…

BetaFlight统一硬件配置文件研读之serial命令

BetaFlight统一硬件配置文件研读之serial命令 1. 源由2. 代码分析3. 实例分析4. 配置情况5. 参考资料 统一硬件配置文件的设计是一种非常好的设计模式,可以将硬件和软件的工作进行解耦。 1. 源由 cli命令中serial是对UART串口的配置,通常情况下BetaFli…

Redo log详解

WAL(Write-Ahead Logging)机制 WAL 的全称是 Write-Ahead Logging,中文称预写式日志(日志先行),是一种数据安全写入机制。就是先写日志,然后再写入磁盘,这样既能提高性能又可以保证数据的安全性。Mysql中的…

基于Python的PROSAIL模型介绍以及使用

1、介绍 PROSAIL是两种模型耦合得到的。 SAIL是冠层尺度的辐射传输模型,把冠层假设成是连续的且具有给定几何形状和密度的水平均匀分布的介质层,从而模拟入射辐射与均匀介质之间的相互作用,具体还是挺复杂的。而PROSPECT就是叶片尺度的辐射传…

Kafka知识概况

Kafka知识概况 Kafka简介Kafka 生产者Kafka BrokerKafka 消费者Kafka-Eagle 监控Kafka-Kraft 模式集成 SpringBoot Kafka简介 消息队列简介: 目 前企业中比较常见的消息队列产 品主 要有 Kafka、ActiveMQ 、RabbitMQ 、RocketMQ 等。在大数据场景主要采用 Kafka 作…

vmware虚拟机安装k8s(之前已经安装过docker)

1、安装开始 先执行:curl https://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | sudo apt-key add 再执行更改源:echo "deb https://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main" >> /etc/apt/sources.list …

redis分布式锁

文章目录 锁的种类一个靠谱分布式锁需要具备的条件和刚需独占性高可用防死锁不乱抢重入性 如何一步一步实现一个完备的分布式锁单机版加锁Redis分布式锁setnx宕机与过期 防死锁防止误删key的问题lua脚本保证原子性 hsetnx 可重入锁简单工厂模式RedisDistributeLockDistributed…

阿里云服务器购买教程(新手入门指南)

阿里云服务器ECS选购指南,阿里云百科分享2023阿里云服务器新手选择流程,选购云服务器有两个入口,一个是选择活动机,只需要选择云服务器地域、系统、带宽即可;另一个是在云服务器页面,自定义选择云服务器配置…

mac下用git客户端生成ssh秘钥并配置到souretree进行使用

一、使用git 生成 ssh 密钥 1、Mac 安装 git 客户端 打开终端,执行命令: $ brew install git2、执行命令 $ git config --global user.name "xxx" 你自己的名字 $ git config --global user.email "xxxxxx.com&q…

深度学习的环境搭建(window+pytorch)

1.检查是否安装CUDA CUDA(Compute Unified Device Architecture)是由 NVIDIA 推出的一种并行计算平台和编程模型,用于利用 NVIDIA GPU(Graphics Processing Unit)的强大计算能力进行高性能计算任务。CUDA 的主要特点是…

App违反Google数据安全政策,解决方案

前言 google隐私政策阶段性会进行更新,时长关注隐私政策变化,避免app被强制下架,影响后续运营工作。 邮件内容 摘录邮件详情 我们在以下区域发现了问题: SPLIT_BUNDLE 2:政策声明,数据安全部分:“https:…

大数据企业应用合作解决方案案例

打造产教融合的就业育人的综合服务平台,给予十余年的数据智能产业实践经验,专注于大数据和人工智能方向。 目前合作的企业案例包括:信访大数据平台解决方案、工业废水处理解决方案、找齐远程监控解决方案、道路运输安全、广电用户服务大数据解…

清洁赛道新势力,米博凭“减法”突围?

在五四青年节这个特殊的日子,方太旗下的高端智能清洁品牌“米博”发布了新一代无滚布洗地机7系列。 5月4日晚,米博以“减法生活,净请7代”为主题,举办了新品发布会。在发布会上,从小红书翻红的董洁作为方太集团米博产…

Windows命令提示行使用指南一

命令提示行使用指南 前言一、起源和发展二、和DOS的关系三、常用命令 前言 cmd 是 Windows 操作系统中的命令行界面(CLI),也称为命令提示符(CMD)或批处理文件。它是 Windows 命令行界面的主要组成部分,用于…

ASK,FSK和PSK

一、ASK,FSK和PSK 数字信号只有有限个离散值,使用数字信号对载波进行调制的方式称为键控(Keying),分为幅度键控(ASK)、频移键控(FSK)和相移键控(PSK)。 幅度键控可以通过乘法器和开关电路来实现,在数字信…

八、(了解即可)MyBatis懒加载(或者叫延迟加载)

文章目录 八、懒加载(了解即可)8.1 为啥需要懒加载?8.2 懒加载是什么?8.3 开启方式8.4 既然fetchType可以控制懒加载那么我仅仅配置fetchType不配置全局的可以吗?8.5 aggressiveLazyLoading是做什么么的?8.6 注意点8.7 案例验证懒加载准备工…

自学Python必须知道的优秀社区

国内学习Python网站: 知乎学习平台:Python - 基础入门 - 知学堂黑马程序员视频库:大数据学习路线2023版-黑马程序员大数据学习路线图菜鸟教程:菜鸟教程 - 学的不仅是技术,更是梦想!极客学院:极…

进阶自动化测试,这3点你一定要知道的...

自动化测试指软件测试的自动化,在预设状态下运行应用程序或系统,预设条件包括正常和异常,最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。 自动化测试框架一般可以分为两个层次,上层是管理整个自动化测试的开发&a…