原理图:
代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
至少在以下集中情况下可以用 Proxy 模式解决问题:
1)创建开销大的对象时候,比如显示一幅大的图片,我们将这个创建的过程交给代理
去完成, GoF 称之为虚代理( Virtual Proxy);
2)为网络上的对象创建一个局部的本地代理, 比如要操作一个网络上的一个对象( 网
络性能不好的时候,问题尤其突出),我们将这个操纵的过程交给一个代理去完成, GoF 称
之为远程代理( Remote Proxy);
3) 对对象进行控制访问的时候, 比如在 Jive 论坛中不同权限的用户(如管理员、 普通
用户等) 将获得不同层次的操作权限, 我们将这个工作交给一个代理去完成, GoF 称之为保
护代理( Protection Proxy)。
根据代理的创建时期,代理模式分为静态代理和动态代理。
- 静态:由程序员创建代理类或特定工具自动生成源代码再对其编译,在程序运行前代理类的 .class 文件就已经存在了。
- 动态:在程序运行时,运用反射机制动态创建而成
静态代理:
package design.proxy;
//抽象主题
interface Subject {
void Request();
}
package design.proxy;
class ProxyTest {
public static void main(String[] args) {
Proxy proxy = new Proxy();
proxy.Request();
}
}
//真实主题
class RealSubject implements Subject {
public void Request() {
System.out.println("访问真实主题方法...");
}
}
//代理
public class Proxy implements Subject {
private RealSubject realSubject;
public void Request() {
if (realSubject == null) {
realSubject = new RealSubject();
}
preRequest();
realSubject.Request();
postRequest();
}
public void preRequest() {
System.out.println("访问真实主题之前的预处理。");
}
public void postRequest() {
System.out.println("访问真实主题之后的后续处理。");
}
}
结果:
访问真实主题之前的预处理。
访问真实主题方法...
访问真实主题之后的后续处理。
静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。可以用动态代理解决这些问题
动态代理:
类图如下:
代码:
package design.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler {
private Object object;
public DynamicProxy(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理 访问真实主题之前的预处理");
Object result = method.invoke(object, args);
System.out.println("动态代理 访问真实主题之后的后续处理");
return result;
}
public static void main(String[] args) {
Subject subject = new RealSubject1(); // 此处只需要用工厂模式,就可以根据业务参数动态提供不同的真实主题
Subject realSubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new
Class[]{Subject.class}, new DynamicProxy(subject));
realSubject.Request();
subject = new RealSubject2();
realSubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), new
Class[]{Subject.class}, new DynamicProxy(subject));
realSubject.Request();
}
}
//真实主题
class RealSubject1 implements Subject {
public void Request() {
System.out.println("访问真实主题1方法...");
}
}
//真实主题
class RealSubject2 implements Subject {
public void Request() {
System.out.println("访问真实主题2方法...");
}
}
结果:
动态代理 访问真实主题之前的预处理
访问真实主题1方法...
动态代理 访问真实主题之后的后续处理
动态代理 访问真实主题之前的预处理
访问真实主题2方法...
动态代理 访问真实主题之后的后续处理
参考文章: