概述:
代理模式:为另一个对象提供一个替身(或占位符),以控制对该对象的访问;
使用代理模式创建代理对象,让代理对象控制某对象的访问,被代理的对象可以是远程(或创建开销大、需要安全控制的)对象。要点:
- 代理角色内部含有对真实角色的引用:从而可以在任何时候操作真实角色对象;
- 代理角色与真实角色实现同一接口:以便可以在任何时候都可以替代真实角色,负责在需要的时候创建(删除)真实角色对象。
- 代理角色通常在将客户端调用传递给真实主题之前(或之后),都要执行某个操作(如检验参数),而非单纯将调用传递给真实角色对象。
一、uml类图
二、(静态)代理 模式的实现
1,主题角色
package static_proxy;//主题角色(抽象)public interface IBuyCar { public void buyCar();}
2,目标角色
View Code
3,代理角色
1 package static_proxy; 2 3 public class BuyCarProxy implements IBuyCar{ 4 private Customer customer;//接收买车客户 5 6 public BuyCarProxy(Customer customer){ 7 this.customer=customer;//接收买车客户 8 } 9 10 @Override11 public void buyCar() { //实现为客户买车12 customer.buyCar();13 }14 15 }
4,测试
1 package static_proxy; 2 3 public class Main { 4 public static void main(String[] args) { 5 Customer customer = new Customer(); 6 customer.setCash(120000); 7 8 BuyCarProxy buyCarProxy = new BuyCarProxy(customer); 9 buyCarProxy.buyCar();10 }11 }
三、(动态)代理 模式的实现(通过 jdk)
JDK提供的动态代理需要实现InvocationHandler
接口的invoke
方法(此方法为整个代理的入口)。
方法签名:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
第一个参数proxy:代理对象
第二个参数目method:目标方法
第三个参数args:目标方法的参数
问题:若使用(静态)代理,则当目标接口需要增加新的方法时,则对应的代理类也需要进行相应的改动,维护工程比较大。故需要(动态)代理
(静态-》动态)目标接口以及目标实现不需要改变,但BuyCarProxy(静态代理类)修改为实现InvocationHandler的处理类:
1,静态代理类 修改 为
1 package dynamic_proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class ProxyHandler implements InvocationHandler{ 7 Object target; 8 9 public ProxyHandler(Object target) {10 this.target=target;11 }12 //验证参数(代理对象处理目标对象前)13 public void before(String param){14 System.out.println("参数检验:" + param);15 }16 @Override17 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {18 this.before(null);19 20 return method.invoke(this.target, args);21 }22 23 24 }
2,测试类(即使增加实现的方法,也不用修改代理)
1 package dynamic_proxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 public class Main { 7 public static void main(String[] args) { 8 //我们要代理的真实对象 9 Customer customer = new Customer();10 //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的11 InvocationHandler handler = new ProxyHandler(customer);12 13 /*14 * 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数15 * 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象16 * 第二个参数customer.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了17 * 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上18 */19 IBuyCar buyCar = (IBuyCar) Proxy.newProxyInstance(handler.getClass().getClassLoader(), customer.getClass().getInterfaces(), handler);20 buyCar.search();21 buyCar.buyCar();22 }23 }