设计模式学习——代理模式(2)
上一篇我们简单介绍了什么是代理模式,但我们说的仅仅是静态代理,所谓静态代理即代理类和目标类在代码中是确定的,因此称为静态,这种方式存在以下问题:
由于在使用时需要提前定义好代理类并实现对应主题的接口方法,随着需要代理的主题增加,代理类也会增加,导致项目中出现大量类情况,不易于项目维护。
那么有没有什么方式可以仅仅在我们需要的时候创建代理呢?答案是:动态代理。
一、什么是动态代理
动态代理就是在实现阶段不需要关心代理谁,而在运行阶段才指定代理哪一个对象。那具体该如果使用呢?我们还是以代购为例,使用了动态代理后整个代购的类图如下:
从类图中我们看到增加了一个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(); } }
我们执行后发现如下报错:
二、动态代理与静态代理的区别
- 静态代理只能通过手动完成代理操作,如果被代理类增加了新的方法,则代理类需要同步增加,违背开闭原则。
- 动态代理采用在运行时动态生成代码的方式,取消了对被代理类的扩展限制,遵循开闭原则。
- 若动态代理要对目标类的增强逻辑进行扩展,结合策略模式,只需要新增策略类便可完成,无需修改代理类的代码。
分类: 设计模式