【设计模式】-代理模式

本文介绍了代理模式的概念,包括静态代理和动态代理。静态代理通过自定义代理类实现额外功能,如日志记录,但存在代码重复和灵活性不足的问题。动态代理利用Java反射机制,在运行时动态生成代理类,解决了静态代理的局限性,实现了功能的集中管理和灵活扩展。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、代理模式

**代理**:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
**目标**:被代理“套用”了非核心逻辑代码的类、对象、方法。
**静态代理**:自己定义代理类或者通过工具提前生成代理类,在程序运行前,代理类的.class文件已经存在。
**动态代理**:代理类是动态生成的。程序运行前,还没有代理类.class文件。

二、例子

声明计算器接口Calculator,包含加减乘除的抽象方法。

public interface Calculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}

计算机实现类

public class CalculatorImpl implements Calculator {
    public int add(int i, int j) {
        return i+j;
    }

    public int sub(int i, int j) {
        return i-j;
    }

    public int mul(int i, int j) {
        return i*j;
    }

    public int div(int i, int j) {
        return i/j;
    }
}

想要在每个方法前打印方法名称+参数,方法执行后增加结果输出,如果直接在实现类修改:

public int add(int i, int j) {
	System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
	int result = i+j;
	System.out.println("[日志] add 方法结束了,结果是:" + result);
	return result;
}

问题:
对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
附加功能分散在各个业务功能方法中,不利于统一维护。
解决方案:
解耦,计算器实现类只关注自己的核心功能,计算。日志交给代理类来完成。

/**
 *  通过静态代理,再方法执行前后加日志
 */
public class CalculatorStaticProxy implements Calculator {
    /**
     *  目标类,代理类中核心方法来自目标类
     */
    private Calculator target;

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

    public int add(int i, int j) {
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
        int result = target.add(i, j);
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] add 方法开始了,结果是:" + i + "," + j);
        return result;
    }

    public int sub(int i, int j) {
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] sub 方法开始了,参数是:" + i + "," + j);
        int result = target.sub(i, j);
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] sub 方法开始了,结果是:" + i + "," + j);
        return result;
    }

    public int mul(int i, int j) {
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] mul 方法开始了,参数是:" + i + "," + j);
        int result = target.mul(i, j);
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] mul 方法开始了,结果是:" + i + "," + j);
        return result;
    }

    public int div(int i, int j) {
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);
        int result = target.div(i, j);
        // 附加功能由代理类中的代理方法来实现
        System.out.println("[日志] add 方法开始了,结果是:" + i + "," + j);
        return result;
    }
}

测试

  @Test
    public void testStaticProxy() {
        /**
         *  静态代理确实实现了解耦,但是由于代码都写死了,完全不具备任何的灵活性。就拿日志功能来
         * 说,将来其他地方也需要附加日志,那还得再声明更多个静态代理类,那就产生了大量重复的代
         * 码,日志功能还是分散的,没有统一管理。
         * 提出进一步的需求:将日志功能集中到一个代理类中,将来有任何日志需求,都通过这一个代理
         * 类来实现。这就需要使用动态代理技术了。
         */
        CalculatorStaticProxy calculatorStaticProxy = new CalculatorStaticProxy(new CalculatorImpl());
        System.out.println(calculatorStaticProxy.add(1, 2));
        System.out.println(calculatorStaticProxy.sub(1, 2));
        System.out.println(calculatorStaticProxy.mul(1, 2));
        System.out.println(calculatorStaticProxy.div(1, 2));
    }

动态代理实现

package com.lucky;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

/**
 * 动态代理有两种:
 * 1、jdk动态代理,要求必须有接口,最终生成的代理类和目标类实现相同的接口
 * 在com.sun.proxy包下,类名为$proxy2
 * 2、cglib动态代理,最终生成的代理类会继承目标类,并且和目标类在相同的包下
 */

public class ProxyFactory {
    private Object target;

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

    public Object getProxy() {

        /**
         * newProxyInstance():创建一个代理实例
         * 其中有三个参数:
         * 1、classLoader:加载动态生成的代理类的类加载器
         * 2、interfaces:目标对象实现的所有接口的class对象所组成的数组
         * 3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接
         口中的抽象方法
         */
        ClassLoader classLoader = target.getClass().getClassLoader();
        Class<?>[] interfaces = target.getClass().getInterfaces();
        InvocationHandler invocationHandler = new InvocationHandler() {
        /**
         * proxy:代理对象
         * method:代理对象需要实现的方法,即其中需要重写的方法
         * args:method所对应方法的参数
         */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object result = null;
                try {
                    System.out.println("[动态代理][日志] " + method.getName() + ",参数:" + Arrays.toString(args));
                    result = method.invoke(target, args);
                    System.out.println("[动态代理][日志] " + method.getName() + ",结果:" + result);
                } catch (Exception e) {
                    e.printStackTrace();
                    System.out.println("[动态代理][日志] " + method.getName() + ",异常:" + e.getMessage());
                } finally {
                    System.out.println("[动态代理][日志] " + method.getName() + ",方法 执行完毕");
                }
                return result;
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

测试

 @Test
    public void test02() {
        ProxyFactory factory = new ProxyFactory(new CalculatorImpl());
        Calculator proxy = (Calculator) factory.getProxy();
        System.out.println(proxy.add(1, 2));
        System.out.println(proxy.div(1, 0));
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值