设计模式之代理模式(静态动态)代理

news2024/9/21 10:59:28

前言:

二十三种设计模式中的一种,属于结构型模式。它的作用就是通过提供一个代理类,让我们在调用目标

方法的时候,不再是直接对目标方法进行调用,而是通过代理类间接调用。让不属于目标方法核心逻辑

的代码从目标方法中剥离出来——解耦。调用目标方法时先调用代理对象的方法,减少对目标方法的调

用和打扰,同时让附加功能能够集中在一起也有利于统一维护。

使用代理前

如下,我们创建了一个接口,然后实现接口方法,模拟了计算器的加法,传入两个数字返回结果。

public interface Calculator {
    int add(int i, int j);
}
public class CalculatorImpl implements Calculator{
    @Override
    public int add(int i, int j) {
        int result = i + j;
        System.out.println("i+j="+result);
        return result;
    }
}

就是简单的调用方法然后返回数据

使用代理后

使用了代理就是相当于代理帮我们去调用方法,可以理解为生活中明星的经纪人

静态代理

public class CalculatorStaticProxy implements Calculator{

    private CalculatorImpl target;

    public CalculatorStaticProxy(CalculatorImpl target) {
        this.target = target;
    }

    @Override
    public int add(int i, int j) {
        System.out.println("日志,方法:add,参数:"+i+","+j);
        int result = target.add(i, j);
        System.out.println("日志,方法:add,结果:" + result);
        return result;
    }

比如我们要在刚刚的add方法中加入一些日志功能,先创建一个代理类,实现接口的add方法,我们在接口类中声明一个CalculatorImpl类型的target,将它私有化,然后给一个构造方法,我们在日志中间加入内部方法,用构造方法传进来的CalculatorImpl类型的target来调用int result = target.add(i, j);即CalculatorImpl类的👇

public class CalculatorImpl implements Calculator{
    @Override
    public int add(int i, int j) {
        int result = i + j;
        System.out.println("i+j="+result);
        return result;
    }
}

我们在测试类里测试一下

public class ProxyTest {
    @Test
    public void testProxy(){
        CalculatorStaticProxy proxy = new  CalculatorStaticProxy(new CalculatorImpl());
        proxy.add(1,2);
    }
}

静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来

说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代

码,日志功能还是分散的,没有统一管理。

提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理

类来实现。这就需要使用动态代理技术了

动态代理

动态代理通过自己的方式创建出代理对象,实际操作时候直接操作代理对象即可,解决了代码冗余的弊端。市面上常见的两种动态代理方式,jdk动态代理和cglib动态代理。

这里演示的是jdk动态代理。

JDK动态代理是jdk自带的,是通过java.lang.reflect.Proxy创建的代理对象,它的创建方式是通过传入java.lang.reflect.InvocationHandler匿名内部类的方式,在通过反射创建代理对象时让代理对象同时实现被代理的接口和java.lang.reflect.InvocationHandler接口,从而达到一个动态代理的目的。因此,jdk动态代理需要被代理对象实现一个接口。

创建一个代理工厂,之前创建对象都是new一个类的构造方法(),现在我们是使用Proxy类的方法,让他代替我们new一个类

public class ProxyFactory {
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    public Object getProxy() {
        //classLoader:加载动态生成的代理类的类加载器
        ClassLoader classLoader = this.getClass().getClassLoader();

        //interfaces:目标对象实现的所有接口的class对象所组成的数组
        Class<?>[] interfaces = target.getClass().getInterfaces();

        /**invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接
         口中的抽象方法*/
        InvocationHandler handler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /**
                 * proxy:代理对象
                 * method:代理对象需要实现的方法,即其中需要重写的方法
                 * args:method所对应方法的参数*/
                System.out.println("日志,方法:" + method.getName() + ",参数:" + Arrays.toString(args));
                Object result = method.invoke(target, args);

                System.out.println("日志,方法:" + method.getName() + ",参数:" + result);
                return result;
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, handler);
    }
}

测试一下

    @Test
    public void testProxy2(){
        ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());
        Calculator proxy =(Calculator) proxyFactory.getProxy();
        proxy.add(1,2);
    }
}

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

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

相关文章

PHP设计模式

目录 一、使用设计模式目的 二、设计模式的七大原则 三、创建型模式&#xff08;构建型模式&#xff09; 1、单例模式 代码实例 2、工厂模式 2.1、工厂模式——简单工厂模式 简单工厂模式的代码实例 2.2、工厂模式——工厂方法模式 工厂方法模式的代码实例 2.3、工厂…

java开发环境配置及问题排查

Java程序必须运行在JVM之上&#xff0c;所以&#xff0c;我们第一件事情就是安装JDK。 JDK(Java Development Kit)&#xff0c;是Java开发工具包&#xff0c;它提供了Java的开发环境(提供了编译器javac等工具&#xff0c;用于将java文件编译为class文件)和运行环境(提 供了JVM…

Java内存模型和线程安全

Java内存模型和线程安全Java内存模型引言volatile关键字synchronized关键字Java线程Java线程安全synchronized锁优化锁优化技巧列举自旋锁锁消除锁粗化具体实现轻量级锁偏向锁Java内存模型 引言 对于多核处理器而言,每个核都会有自己单独的高速缓存,又因为这多个处理器共享同一…

JavaWeb-会话技术

JavaWeb-会话技术 1&#xff0c;会话跟踪技术的概述 对于会话跟踪这四个词&#xff0c;我们需要拆开来进行解释&#xff0c;首先要理解什么是会话&#xff0c;然后再去理解什么是会话跟踪: 会话:用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&#xff…

反射机制.

文章目录概述两个疑问关于java.lang.Class的理解获取Class实例的方式哪些类型可以有Class对象了解类的加载器掌握加载配置文件的另一种方式创建运行时类的对象体会动态性获取运行时类的完整结构调用运行时类的制定结构每日一考动态代理概述 1、反射是动态语言的关键 2、动态语…

使用Docker打包镜像并发布

1、docker介绍 Docker 是一个开源的应用容器引擎&#xff0c;以镜像的形式进行发布。docker的图标是一个大鲸鱼驮着许多集装箱在海上航行。大鲸鱼就是docker&#xff0c;集装箱就是一个个容器。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口&#xff0c;每个容器都…

高级Spring之BeanFactory 与 ApplicationContext 的区别

ApplicationContext接口 SpringBootApplication public class A01 {private static final Logger log LoggerFactory.getLogger(A01.class);public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {//启动SpringBoot程序…

Python Scipy 显著性检验

Scipy 显著性检验显著性检验&#xff08;significance test&#xff09;就是事先对总体&#xff08;随机变量&#xff09;的参数或总体分布形式做出一个假设&#xff0c;然后利用样本信息来判断这个假设&#xff08;备择假设&#xff09;是否合理&#xff0c;即判断总体的真实情…

Linux基本功系列之userdel命令实战

春节马上要到了&#xff0c;大街上到处都是张灯结彩&#xff0c;喜气洋洋的景象&#xff0c;你们那里也开始了吗&#xff1f; 文章目录一. userdel命令概述二. 语法格式及常用选项语法格式及常用参数三. 参考案例3.1 删除用户但不删除家目录等相关的文件3.2 把用户彻底删除3.3 …

【Linux05-进程控制】进程创建、进程等待、进程退出、进程程序替换(附简易shell实现)

前言 本期分享进程控制的内容。 博主水平有限&#xff0c;不足之处望请斧正&#xff01; 进程的控制主要分为四点&#xff1a; 进程创建进程退出进程等待进程程序替换 进程创建 怎么创建 通过fork创建。 #fork 是什么 创建子进程的函数。&#xff08;使用已经介绍过&am…

Python基础学习 -- 概念

一、变量python的变量定义起来比较随意&#xff0c;不用定义数据类型a123b"123"系统会自动识别a为数值&#xff0c;b为字符串二、关键字定义变量名字的时候&#xff0c;要避开下面的关键字&#xff0c;但是可以通过大小写区分&#xff0c;as123;#错误定义As123;print…

阿里云服务器ECS

云服务器 ECS云服务器ECS&#xff08;Elastic Compute Service&#xff09;是一种简单高效、处理能力可弹性伸缩的计算服务。帮助您构建更稳定、安全的应用&#xff0c;提升运维效率&#xff0c;降低IT成本&#xff0c;使您更专注于核心业务创新。为什么选择云服务器ECS选择云服…

音频如何分割成两段音频?这些实用方法值得收藏

有些时候&#xff0c;我们从网上下载的音频素材可能会出现体积较大、播放时间长等情况&#xff0c;而我们却只需要其中的一小段。这个时候我们就需要借助一些音频分割软件来将重要的音频片段提取出来&#xff0c;从而有助于缩小音频文件的占比以及存储。那么如何如何分割音频呢…

JVM进修之路(一)程序计数器与虚拟机栈

JVM 定义&#xff1a;JVM:Java Virtual Machine&#xff0c;也就是Java运行时所需要的环境&#xff08;Java二进制字节码运行时所需要的环境&#xff09; 好处&#xff1a; 1.java代码一次编写&#xff0c;跨平台运行 2.自动内存管理&#xff0c;垃圾回收 3.数组下标越界检查 4…

千锋Node.js学习笔记

千锋Node.js学习笔记 文章目录千锋Node.js学习笔记写在前面1. 认识Node.js2. NVM3. NPM4. NRM5. NPX6. 模块/包与CommonJS7. 常用内置模块1. url2. querystring3. http4. 跨域jsonpcorsmiddleware&#xff08;http-proxy-middleware&#xff09;5. 爬虫6. events7. File System…

Mysql常用命令练习(一)

Mysql常用命令练习&#xff08;一&#xff09;一、数据库的三层结构二、数据库2.1、创建数据库2.2、查看、删除数据库2.3、备份和恢复数据库三、表3.1、创建表mysql常用的数据类型(列类型)创建表查看表查看表结构练习3.2、修改表修改表名修改表的字符集添加列修改列删除列练习3…

轻量级网络模型ShuffleNet

在学习ShuffleNet内容前需要简单了解卷积神经网络和MobileNet的相关内容&#xff0c;大家可以去看我之前的一篇博客MobileNet发展脉络&#xff08;V1-V2-V3&#xff09;&#xff0c;&#x1f197;&#xff0c;接下来步入正题~卷积神经网络被广泛应用在图像分类、目标检测等视觉…

易盾sdk引起项目的整体耗时问题?

大家好&#xff1a; 我是烤鸭。今年年初的时候&#xff0c;项目接入易盾sdk之后&#xff0c;随着接口调用次数增多(用到易盾sdk的接口)&#xff0c;项目整体性能变差。写篇文章做个复盘记录&#xff0c;其实同事已经写过了&#xff0c;我借鉴部分再拓展一些。 问题描述 突然收…

【JavaEE初阶】第五节.多线程 ( 基础篇 ) 线程安全问题(上篇)

目录 文章目录 前言 一、线程安全的概述 1.1 什么是线程安全问题 1.2 存在线程安全问题的实例 二、线程安全问题及其解决办法 2.1 案例分析 2.2 造成线程不安全的原因 2.3 线程加锁操作解决原子性 问题 &#xff1b; 2.3.1 什么是加锁 2.3.2 使用 synchronized关键字…

爆品跟卖商家必读:2023年快速入局TikTok选品5大关键

TikTok商业进程一直有在发展&#xff0c;开启东南亚小店&#xff0c;美国小店内邀……有吸引了不少外贸工厂和传统跨境电商卖家等玩家入局。2022年这一年&#xff0c;不管是直播带货&#xff0c;短视频带货&#xff0c;还是广告投流&#xff0c;数据都有新的变化。据报道&#…