一、定义
代理模式,就是为其他对象提供代理以控制对这个对象的访问。用生活中的例子来讲,就像我们生活中打官司一样,我不需要直接去处理官司,因为我们不懂法律,所以就需要一个专业的律师来替我们处理。我只需要提供一些材料,具体怎么打,那就是律师该做的事情了。
从网上找了一张用来描述代理模式的UML类图
二、使用场景
当无法访问或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。
三、静态代理
我们通过一个例子来实现上面的UML图。
抽象主题类(Subject),委托类和代理对象要实现的相同接口。
public interface Subject {
void request();
}
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("静态代理:我是被代理的对象");
}
}
代理类(Proxy)
public class ProxySubject implements Subject {
Subject realSubject;
public ProxySubject(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public void visit() {
realSubject.request();
}
}
客户类
public class Client {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
Subject proxySubject = new ProxySubject(realSubject);
proxySubject.visit();
}
}
四、动态代理
通过上面的实践,相信大家基本上掌握了静态代理的使用。那么接下来我要介绍的是动态代理。
动态代理是通过反射机制动态生成代理者的对象,也就是说我们在code阶段不需要知道代理谁,代理谁我们将会在执行阶段决定。
public class DynamicProxy implements InvocationHandler {
// 被代理的类引用
private Object obj;
public DynamicProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 调用被代理类对象的的方法
Object result = method.invoke(obj, args);
return result;
}
}
如上代码所示,我们声明一个Object的引用,该引用将指向被代理类,而我们调用被代理类的具体方法则在invoke方法中执行。也就是说我们原来由代理类所做的工作现在由InvocationHandler来处理,不再需要关心到底代理谁。
public class Client {
public static void main(String[] args) {
// 构造一个动态代理
Subject realSubject=new RealSubject();
DynamicProxy proxyHandler = new DynamicProxy(realSubject);
ClassLoader loader = realSubject.getClass().getClassLoader();
Subject subject = (Subject) Proxy.newProxyInstance(loader,
new Class[] { Subject.class }, proxyHandler);
subject.request();
}
}
五、总结
通过上面的介绍,我们可以很清楚的看到动态代理可以通过一个代理类来实现多个被代理类,其实质就是代理者与被代理的解耦,使两者没有直接耦合关系。
相对而言静态代理则只能为给接口下的实现类做代理,如果接口不同就需要定义不同的代理类,较为复杂。但是静态代理比较符合面向对象原则。在开发时具体使用哪种方式来实现代理,看你自己偏好。
静态代理和动态代理是通过Code方面来区分代理模式的两种方式。我们也可以从其适用范围来区分不同类型的代理实现。
1、远程代理:为某个对象在不同的内存地址空间提供局部代理。使系统可以将Server部分的实现隐藏,以便Client可以不必考虑Server的存在。
2、虚拟代理:使用一个代理对象表示一个十分耗资源的对象并在真正需要时才创建。
3、保护代理:使用代理控制对原始对象的访问。该类型的代理常被用于原始对象有不同访问权限的情况。
4、智能引用:在访问原始对象时执行一些自己的附加操作并对指向原始对象的引用计数。
这里要注意的是,静态和动态代理都可以应用于上述4种情形,两者是各自独立的变化。
区别:动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强
参考资料:《Android源码设计模式解析与实践》