代理模式是GoF23种Java常用设计模式之一,采用了对象的结构模式,能够为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一 个客户不想直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介作用。
代理模式的特征
代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的 对象的相关方法,来提供特定的服务。
代理模式涉及到的角色
代理模式一般涉及到三个角色:(1)抽象角色:声明真实对象和代理对象的共同接口,可以是抽象类也可以是借口。
(2)代理角色:代理对象内部包含有真实角色的引用,从而可以操作真实角色,同时代理对象与真实对象有相同的接口,能在任何时候代替真实对象,同时代理对象可以在执行真实对象前后加入特定的逻辑以实现功能的扩展。
(3)真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
其UML图如下:
实例
以《Java与模式》中的示例为例
//抽象角色
public abstract class Subject {
abstract public void request();
}
//真实角色
public class RealSubject extends Subject {
public RealSubject() {
super();
}
@Override
public void request() {
System.out.println("From real subject.");
}
}
//代理角色
public class ProxySubject extends Subject {
private RealSubject realSubject; // 以真实角色作为代理角色的属性
public ProxySubject() {
}
public void request() { // 该方法封装了真实对象的request方法
preRequest();
if (realSubject == null) {
realSubject = new RealSubject();
}
realSubject.request(); // 此处执行真实对象的request方法
postRequest();
}
private void preRequest() {
// something you want to do before requesting
}
private void postRequest() {
// something you want to do after requesting
}
}
//Test
public class TestProxy {
public static void main(String[] args) {
Subject sub = new ProxySubject();
sub.request();
}
}
从上面的代码我们可以看出,客户实际调用的是RealSubject类的request()方法,现在用ProxySubject来代理RealSubject类,同样达到目的,同时还封装了其他方法(preRequest(),postRequest()),可以处理一些其他问题。
上面代码实现的代理模式中,真实角色是事先已经定义好的,并将其作为代理对象的内部属性,这种代理模式称之为静态代理。而实际使用中,一个真实角色必须对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这就是我们后面要探讨的动态代理了。
使用场景
代理模式使用场景非常多,如面向切面编程(Spring中的AOP),虚代理模式(hibernate中的懒加载),保护代理(权限服务控制),远程代理(Java中的RMI技术)等。
常见的代理有哪些一、按照代理的创建时期,代理类可以分为两种。
(1)静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
(2)动态代理:在程序运行时,运用反射机制动态创建而成。
二、按照代理用途来分类
(1)远程代理(Remote Proxy) -可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。(2)虚拟代理(Virtual Proxy) – 允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。
(3)写入时复制代理(Copy-On-Write Proxy) – 用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。是虚拟代理的一个变体。
(4)保护代理(Protection (Access)Proxy) – 为不同的客户提供不同级别的目标对象访问权限
(5)缓存代理(Cache Proxy) – 为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。
(6)防火墙代理(Firewall Proxy) – 控制网络资源的访问,保护主题免于恶意客户的侵害。
(7)同步代理(SynchronizationProxy) – 在多线程的情况下为主题提供安全的访问。
(8)智能引用代理(Smart ReferenceProxy) - 当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
(9)复杂隐藏代理(Complexity HidingProxy) – 用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Fa?ade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。