代理模式
代理,就是一个人或者一个机构代表另一个人或者另一个机构采取行动。一些情况下,一个客户不想或者不能直接引用一个对象,而代理对象能在客户对象和目标对象之间起到中介作用。
代理的种类
按照使用目的来划分,代理对象可以分为以下几种:
(1) 远程(Remote)代理:为一个位于不同的地址空间的对象提供一个局域代表对象。这个不同的地址空间,可以再本机中,也可以再另一台机器中。远程代理又叫大使(Ambassador)。
(2) 虚拟(Virtual)代理:根据需要创建一个资源消耗很大的对象,使得次对象只有在需要的时候才会被真正创建。
(3) Copy-on-Write代理:虚拟代理的一种。把复制(克隆)拖延到只有在客户端需要时,才真正采取行动。
(4) 保护(Protect or Access)代理:控制对一个对象的访问,如果需要,可以给不同的用户提供不同级别的使用权限。
(5) Cache 代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。
(6) 防火墙(FireWall)代理:保护目标,不让恶意的用户接近。
(7) 同步化(Synchronization)代理:使几个用户能同事使用一个对象而没有冲突。
(8) 智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。
在所有的代理模式中, 远程(Remote)代理、虚拟(Virtual)代理、保护(Protect or Access)代理和智能引用(Smart Reference)代理是最为常见的代理模式。
代理模式的结构
代理模式所涉及的角色有:
(1) 抽象主题角色:声明了真实主题和代理主题的共同接口,这样一来在任何可以使用真实主题的地方都可以使用代理主题。
(2) 代理主题(Proxy)角色:代理主题角色内部含有对真实主题的引用。从而可以在任何时候操作真实主题对象;代理主题角色提供一个与真实主题角色相同的接口,以便可以在任何时候都可以替代真实主题;控制对真实主题的引用,负责在需要的时候创建真实主题对象(删除真实主题对象);代理角色通常在将客户端调用传递给真实的主题之前或之后,都要执行某个操作,而不是单纯地将调用传递给真实主题对象。
(3) 真实主题角色:定义了代理角色所代表的真实对象。
简单是示意性实现类图如下:

抽象主题角色示意性代码:Subject.java
package com.model.structural.proxy;
/**
* 代理模式:
* 抽象主题角色
* */
public abstract class Subject {
public abstract void request();
}
真实主题角色示意性代码:RealSubject.java
package com.model.structural.proxy;
/**
* 真实主题角色
* */
public class RealSubject extends Subject{
/**
* 构造函数
* */
public RealSubject(){
}
/**
* 实现请求的方法
* */
public void request() {
System.out.println("From real subject!");
}
}
代理主题角色示意性代码:ProxySubject.java
package com.model.structural.proxy;
/**
* 代理主题角色
* */
public class ProxySubject extends Subject{
private RealSubject realSubject;
/**
* 构造子
**/
public ProxySubject(){
}
public void request() {
preRequest();
if(realSubject==null){
realSubject = new RealSubject();
}
realSubject.request();
postRequest();
}
/**
* 请求前的操作
* */
private void preRequest(){
//业务逻辑代码
System.out.println("this is the preRequest method!");
}
/**
* 请求后的操作
* */
private void postRequest(){
//业务逻辑代码
System.out.println("this is the postRequest method!");
}
}
调用代理主题:AppRun.java
package com.model.structural.proxy;
public class AppRun {
/**
* 调用代理模式
* */
public static void main(String args []){
Subject subject = new ProxySubject();
subject.request();
}
}
代理模式的工作流程:首先代理主题并不改变主题的接口,因为模式的用意不让客户端感到代理的存在;其次代理使用委派将客户端的调用委派给真实的主题对象,换而言之,代理主题起到的是一个传递请求的作用;最后代理主题在传递请求之前和之后都可以执行特定的操作,而不是单纯传递请求。
代理模式的优点和缺点
根据代理种类的不同,代理模式有不同的特点。
远程代理
优点是系统可以将网络的细节隐藏起来,使客户端不必考虑网络的存在。客户端完全可以认为被代理的对象是局域网的而不是远程的,而代理对象承担了大部分的网络通信工作,由于客户端可能没有意识到会启动一个消耗时间的远程调用,因此客户端没有必要的思想准备。
虚拟代理
使用虚拟代理模式的优点是代理对象可以在需要的时候才被代理的对象加载,代理可以对加载的过程加以必要的优化。当一个模块的加载非常消耗资源时,虚拟代理的优点就非常明显。
保护代理
保护代理的优点是,它可以在运行时间对用户的有关权限进行检查,然后再核实后决定将调用传递给被代理的对象。
智能引用代理
在访问一个对象时,可以执行一些内务(Housekeeping)处理操作,比如计算操作等。
代理模式与其他模式的关系
适配器模式
适配器模式与代理模式很相像,他们都可以视为一个对象提供一个前置的接口。但是适配器模式的用意是改变所考虑的对象的接口,使之拥有新的功能。而代理模式不改变所代理对象的接口,不需要拥有新的功能,只是通过代理改变用户的调用方式使原有的功能拥有更快的效率、安全性等。适配器模式侧重的是改变对象的功能,代理模式则侧重用使用对象的方式。
装饰模式
装饰模式与所装饰的对象具有相同的接口,因此这两种模式也有可能混淆。但是,装饰模式应当为所装饰的对象提供增强功能,而代理模式对对象的使用施加控制,并不提供对象本事功能增强功能。
门面模式
有时候门面模式兼任代理的责任。门面对象可能是一个位于另一个地址空间的子系统的远程代理;有时候,门面模式兼任保护代理的角色,检查使用者的权限;有时候,门面模式负责记录子系统被调用的次数,因此兼任智能引用代理的角色,有时候,门面模式兼任虚拟代理的角色,特别是当子系统的加载耗费时间和资源的时候。