设计模式学习——代理模式(2)

简介: 上一篇我们简单介绍了什么是代理模式,但我们说的仅仅是静态代理,所谓静态代理即代理类和目标类在代码中是确定的,因此称为静态,这种方式存在以下问题: 由于在使用时需要提前定义好代理类并实现对应主题的接口方法,随着需要代理的主题增加,代理类也会增加,导致项目中出现大量类情况,不易于项目维护。 那么有没有什

设计模式学习——代理模式(2)


上一篇我们简单介绍了什么是代理模式,但我们说的仅仅是静态代理,所谓静态代理即代理类和目标类在代码中是确定的,因此称为静态,这种方式存在以下问题:


由于在使用时需要提前定义好代理类并实现对应主题的接口方法,随着需要代理的主题增加,代理类也会增加,导致项目中出现大量类情况,不易于项目维护。


那么有没有什么方式可以仅仅在我们需要的时候创建代理呢?答案是:动态代理


一、什么是动态代理


动态代理就是在实现阶段不需要关心代理谁,而在运行阶段才指定代理哪一个对象。那具体该如果使用呢?我们还是以代购为例,使用了动态代理后整个代购的类图如下:


微信图片_20220428110203.png


从类图中我们看到增加了一个InvocationHandler和PaymentIH,他俩的作用就是产生一个对象的代理对象,其中Invocation是JDK提供的动态代理接口,对被代理类的方法进行代理,接下来我们看下具体代码的实现:


(1)PaymentIH

public class PaymentIH implements InvocationHandler {
    private Object obj;
    public PaymentIH(Object obj) {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("前往海外某一大型商场");
        Object result = method.invoke(obj, args);
        System.out.println("携带商品回国");
        return result;
    }
}


其中invoke方法是InvocationHandler定义的必须实现的,它完成对真实方法的调用。


(2)客户端代码


public class Main {
    public static void main(String[] args)
    {
        IPaymentService paymentService = new WatchPaymentService();
        PaymentIH paymentIH = new PaymentIH(paymentService);
        IPaymentService proxy = (IPaymentService) Proxy.newProxyInstance(
                paymentService.getClass().getClassLoader(),
                new Class[] {IPaymentService.class}, paymentIH);
        proxy.pay();
    }
}


我们通过Porxy.newProxyInstance生成代理对象,此方法参数说明如下:


  • ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的


  • Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型


  • InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,把当前执行目标对象的方法作为参数传入

其实在这里我们也就会发现,使用JDK的动态代理有一个限制,那就是被代理类需要实现接口,否则无法代理。


我们来验证一下,我们将客户端代码修改如下后执行:


// WatchPaymentService去掉接口
public class WatchPaymentService {
    public void pay() {
        System.out.println("购买一块浪琴手表");
    }
}
public class Main {
    public static void main(String[] args)
    {
        WatchPaymentService paymentService = new WatchPaymentService();
        PaymentIH paymentIH = new PaymentIH(paymentService);
        IPaymentService proxy = (IPaymentService) Proxy.newProxyInstance(
                paymentService.getClass().getClassLoader(),
                new Class[] {WatchPaymentService.class}, paymentIH);
        proxy.pay();
    }
}


我们执行后发现如下报错:


微信图片_20220428110210.png


二、动态代理与静态代理的区别


  • 静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,则代理类需要同步增加,违背开闭原则。


  • 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。


  • 若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。


分类: 设计模式

相关文章
|
2月前
|
设计模式 缓存 安全
设计模式——代理模式
静态代理、JDK动态代理、Cglib 代理
设计模式——代理模式
|
2月前
|
设计模式 Java 数据安全/隐私保护
Java设计模式-代理模式(7)
Java设计模式-代理模式(7)
|
3月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
3月前
|
设计模式
设计模式的基础问题之代理模式在工作中的问题如何解决
设计模式的基础问题之代理模式在工作中的问题如何解决
|
5月前
|
设计模式 存储 算法
设计模式学习心得之五种创建者模式(2)
设计模式学习心得之五种创建者模式(2)
45 2
|
4月前
|
设计模式 算法 Go
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
iLogtail设计模式问题之代理模式在iLogtail中是如何应用的
|
4月前
|
设计模式 缓存 JavaScript
js设计模式【详解】—— 代理模式
js设计模式【详解】—— 代理模式
32 0
|
5月前
|
设计模式 监控 安全
设计模式之代理模式(Java)
设计模式之代理模式(Java)
|
5月前
|
设计模式 安全 Java
Java设计模式:代理模式的静态和动态之分(八)
Java设计模式:代理模式的静态和动态之分(八)
|
5月前
|
设计模式 Java
Java设计模式之代理模式详解
Java设计模式之代理模式详解