代理模式Proxy
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11401233.html
1. 定义
为其他对象提供一种代理以控制这个对象的访问。
2. 结构图
Proxy:代理对象。通常具有如下功能。
- 实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象。
- 保存一个指向具体目标对象的引用,可以在需要的时候调用具体的目标对象。
- 可以控制对具体目标对象的访问,并可以负责创建和删除它。
Subject:目标接口,定义代理和具体目标对象的接口,这样就可以在任何使用具体目标对象的地方使用代理对象。
RealSubject:具体的目标对象,真正实现目标接口要求的功能。
3. 本质
代理模式的本质:控制对象访问。
4. Code Demo
Subject.java
1 package org.fool.dp.proxy; 2 3 public interface Subject { 4 void request(); 5 }
RealSubject.java
1 package org.fool.dp.proxy; 2 3 public class RealSubject implements Subject { 4 @Override 5 public void request() { 6 System.out.println("real subject invoked..."); 7 } 8 }
ProxySubject.java
1 package org.fool.dp.proxy; 2 3 public class ProxySubject implements Subject { 4 private RealSubject realSubject; 5 6 @Override 7 public void request() { 8 System.out.println("proxy start..."); 9 10 if (null == realSubject) { 11 realSubject = new RealSubject(); 12 } 13 14 realSubject.request(); 15 16 System.out.println("proxy end..."); 17 } 18 }
Client.java
1 package org.fool.dp.proxy; 2 3 public class Client { 4 public static void main(String[] args) { 5 Subject proxySubject = new ProxySubject(); 6 proxySubject.request(); 7 } 8 }
5. 动态代理
Java对代理模式提供了内建的支持,在java.lang.reflect包下面,提供了一个Proxy的类和一个InvocationHandler的接口。
通常把前面自己实现的代理模式称为Java的静态代理。这种实现方式有一个较大的缺点,就是如果Subject接口发生变化,那么代理类和具体的目标实现都要变化,不是很灵活。而使用Java内建的对代理模式支持的功能来实现则没有这个问题。
通常把使用Java内建的对代理模式支持的功能来实现的代理称为Java的动态代理。动态代理跟静态代理相比,明显的变化是:静态代理实现的时候,在Subject接口上定义很多的方法,代理类里面自然也要实现很多方法;而动态代理实现的时候,虽然Subject接口上定义了很多方法,但是动态代理类始终只有一个invoke方法。这样,当Subject接口发生变化的时候,动态代理的接口就不需要跟着变化了。
Java的动态代理目前只能代理接口,基本的实现是依靠Java的反射机制和动态生成class的技术,来动态生成被代理的接口的实现对象。
代理模式在客户和被客户访问的对象之间,引入了一定程度的间接性,客户是直接使用代理,让代理来与被访问的对象进行交互。不同的代理类型,这种附加的间接性有不同的用途,也就具有不同的特点。
动态代理Demo
Subject.java
1 package org.fool.dp.dynamicproxy; 2 3 public interface Subject { 4 void request(); 5 }
RealSubject.java
1 package org.fool.dp.dynamicproxy; 2 3 public class RealSubject implements Subject { 4 @Override 5 public void request() { 6 System.out.println("real subject invoked..."); 7 } 8 }
DynamicSubject.java
1 package org.fool.dp.dynamicproxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class DynamicSubject implements InvocationHandler { 7 private Object subject; 8 9 public DynamicSubject(Object subject) { 10 this.subject = subject; 11 } 12 13 @Override 14 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 15 System.out.println("before calling: " + method); 16 17 method.invoke(subject, args); 18 19 System.out.println("after calling: " + method); 20 21 return null; 22 } 23 }
Client.java
1 package org.fool.dp.dynamicproxy; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Proxy; 5 6 public class Client { 7 public static void main(String[] args) { 8 Subject realSubject = new RealSubject(); 9 10 InvocationHandler handler = new DynamicSubject(realSubject); 11 12 Class<? extends InvocationHandler> handlerClass = handler.getClass(); 13 14 Subject proxySubject = (Subject) Proxy.newProxyInstance(handlerClass.getClassLoader(), 15 realSubject.getClass().getInterfaces(), handler); 16 17 proxySubject.request(); 18 } 19 }