代理模式:为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
通过上面的描述,我们知道在代理模式中存在三个角色。
代理接口:subject。
代理类:ProxySubject。
委托类:RealSubject。
代理类和委托类都实现了代理接口。代理类持有一个委托类的实例。
静态代理
根据上面的描述,可以写出一个简单的代理模式Demo。
代理接口
public interface Subject {
public void doTast();
}
委托类
public class RealSubject implements Subject{
@Override
public void doTast() {
// TODO Auto-generated method stub
System.out.println("RealSubject doTast");
}
}
代理类
public class ProxySubject implements Subject{
private Subject delegate;
public ProxySubject(Subject delegate) {
// TODO Auto-generated constructor stub
this.delegate = delegate;
}
@Override
public void doTast() {
// TODO Auto-generated method stub
System.out.println("ProxySubject doTast");
delegate.doTast();
}
}
客户端调用
RealSubject mRealSubject = new RealSubject();
ProxySubject mProxySubject = new ProxySubject(mRealSubject);//代理类去持有委托类的实例
mProxySubject.doTast();//代理类去执行任务
上面的方式就是静态代理模式了,在代码运行前就已经存在了代理类的class编译文件。
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
除了静态代理,JAVA还提供了动态代理。
动态代理
动态代理类是在程序运行期间由JVM根据反射等机制动态的生成,所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。
JAVA提供了实现动态代理的API。我们先来看看动态代理实现步骤。
1. 实现InvocationHandler接口创建自己的调用处理器
2.创建动态代理。
3.动态创建代理类。
先来看看怎么去创建自己的调用处理器
public class DynamicSubject implements InvocationHandler{
private Object delegate;
public DynamicSubject(Object delegate) {
// TODO Auto-generated constructor stub
this.delegate = delegate;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Object result=method.invoke(delegate, args);
return result;
}
}
接下来对客户端调用中代码做修改。
Subject mRealSubject = new RealSubject();
//创建动态代理
DynamicSubject mDynamicSubject = new DynamicSubject(mRealSubject);
ClassLoader loader=mRealSubject.getClass().getClassLoader();
//动态创建代理类
Subject ProxySubject = (Subject)Proxy.newProxyInstance(loader,new Class[]{Subject.class},mDynamicSubject);
ProxySubject.doTast();