代理是基本的设计模式之一,它是为了提供额外的或不同的操作,而插入的用来代理"实际"对象的对象。这些操作通常涉及与”实际“对象的通信,因此代理通常充当着中间人的角色。下面的一个用例展示代理结构的简单示例。
接口:
/** * 接口 * @author Arts&Crafts * */ public interface Interface { void doSomething(); void somethingElse(String arg); }
实际类:
1 /** 2 * 实际类 3 * @author Arts&Crafts 4 * 5 */ 6 public class RealObject implements Interface { 7 8 @Override 9 public void doSomething() { 10 System.out.println("RealObject.doSomething()"); 11 } 12 13 @Override 14 public void somethingElse(String arg) { 15 System.out.println("RealObject.somethingElse() " + arg); 16 } 17 18 }
代理类:
1 /** 2 * 代理类 3 * 4 * @author Arts&Crafts 5 * 6 */ 7 public class SimpleProxy implements Interface { 8 private Interface proxied; 9 10 public SimpleProxy(Interface proxy) { 11 this.proxied = proxy; 12 } 13 14 @Override 15 public void doSomething() { 16 System.out.println("SimpleProxy.doSomething()"); 17 proxied.doSomething(); 18 } 19 20 @Override 21 public void somethingElse(String arg) { 22 System.out.println("SimpleProxy.somethingElse() " + arg); 23 proxied.doSomething(); 24 } 25 26 }
测试:
1 public class SimpleProxyDemo { 2 public static void consumer(Interface iface){ 3 iface.doSomething(); 4 iface.somethingElse("Hello World"); 5 } 6 7 /** 8 * @param args 9 */ 10 public static void main(String[] args) { 11 consumer(new RealObject()); 12 System.out.println(); 13 consumer(new SimpleProxy(new RealObject())); 14 } 15 16 }
因为consumer()接受的Interface,所以它无法知道正在获取的到底是RealObject还是SimpleProxy,因为这二者都实现了Interface。但是SimpleProxy已经被插入到客户端和RealObkect之间,因此它会执行操作,然后调用RealObject上相同的方法。
在任何时刻,只要你想要将额外的操作从“实际”对象中分离到不同的地方,特别是当你希望能够很容易地做出修改,从没有使用额外操作转换为使用这些操作,或者反过来,代理就显得很有用(设计模式的关键是封装修改——因此你需要修改事务以证明这种模式的正确性)。例如,如果你希望跟踪对RealObject中的方法的调用,或者希望度量这些调用的开销,那么你应该怎么样做呢?这些代码肯定是你不希望将其并到运用中的代码,因此代理使得你可以很容易地添加或移除它们。
Java的动态代理比代理的思想更向前迈进了一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所在的所有调用都会被重定向到单一的调用处理器上,它的工作是揭示调用的类型并确定相应的对策。下面是用动态代理重写:
动态代理调用处理器类:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 4 public class DynamicProxyHandler implements InvocationHandler { 5 private Object proxied; 6 7 public DynamicProxyHandler(Object proxied) { 8 this.proxied = proxied; 9 } 10 11 @Override 12 public Object invoke(Object proxy, Method method, Object[] args) 13 throws Throwable { 14 System.out.println("*** proxy:" + proxy.getClass() + ". method: " 15 + method + ". args:" + args); 16 if (args != null) 17 for (Object arg : args) 18 System.out.println(" " + arg); 19 Object result = method.invoke(proxied, args); 20 return result; 21 } 22 23 }
测试类:
1 import java.lang.reflect.Proxy; 2 3 import org.jdk.staticproxy.Interface; 4 import org.jdk.staticproxy.RealObject; 5 6 public class SimpleDynamicProxyDemo { 7 public static void consumer(Interface iface) { 8 iface.doSomething(); 9 iface.somethingElse("Hello World"); 10 } 11 12 public static void main(String[] args) { 13 RealObject real = new RealObject(); 14 consumer(real); 15 System.out.println(); 16 Interface proxy = (Interface) Proxy.newProxyInstance( 17 Interface.class.getClassLoader(), 18 new Class[] { Interface.class }, new DynamicProxyHandler(real)); 19 consumer(proxy); 20 } 21 }
通过调用静态方法Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望该代理实现的接口列表(不是类或抽象类),以及InvocationHandler接口的一个实现。动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造器传递给一个“实际”对象的引用,从而使得调用处理器在执行其中任务时,可以将请求转发。
invoke()方法中传递进来了代理对象,以放你需要区分请求的来源,但是在很多情况下,帮你并不关心这一点。然而,在invoke()内部,在代理上调用方法时需要格外当心,因为对接口的调用将被重定向为对代理的调用。