代理模式(Proxy)
代理模式是常用的 JAVA 设计模式,它的特征是代理类与委托类实现同样的接口。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后 处理消息等。
代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
作用
给某个对象提供一个代理对象,并由代理对象控制原对象的引用。代理对象和真实对象实现相同的接口,使得任何使用真实对象的地方都可以使用代理对象,代理对象内部含有对真实对象的引用,再将调用传递给真实对象之前或之后执行一些额外的操作,达到控制真实对象的目的。
本质
控制对象的访问。使用场景
代理模式使用场景非常多,如:面向切面编程(Spring中的AOP),
虚代理模式(hibernate中的懒加载),
保护代理(权限服务控制),
远程代理(Java中的RMI技术)等。
代理模式的分类
按照代理的创建时期,代理类可以分为两种:(1)静态代理: 由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
(2)动态代理: 在程序运行时,运用反射机制动态创建而成。
按照代理用途来分类:
(1) 虚代理: 根据需求来创建开销很大的对象,该对象只有在需要的时候才会被真正的被创建。
(2) 远程代理: 用来在不同的地址空间上代表同一对象,这个不同的地址空间可以使在本机也可以是在其他机器上。在Java里面最典型的就是RMI技术。
(3) 保护代理: 控制原始对象的访问,如果有需要,可以给不同的用户提供不同的访问权限,以控制他们对原始对象的访问。
(4) Cache代理: 为那些昂贵操作的结构提供临时的存储空间,以便多个客户端可以共享这些结果。
(5) 智能代理: 在访问对象时执行一些附加操作,比如,对指向实际对象的引用计数,第一次引用一个持久对象时,将它装入内存等。
(6) 防火墙代理: 保护对象不被恶意程序访问和操作。
(7) 同步代理: 使多个用户能够同时访问目标对象而不发生冲突。
(8) Copy-on-write代理:在客户端操作的时候,只有对象确实改变了才会真的拷贝一个目标对象,算是虚代理的一个分支。
示例代码
一般情况下代理模式需要三个角色
A. 真实角色:也就是我们需要引用的那个类。
B. 抽象角色:主要用来声明代理类和真实类的共同接口。代理类和真实类都需要实现该接口。
C. 代理角色:代理角色内部包含对真实角色的引用,从而使客户端可以操作真实的对象,同时代理角色和真实角色拥有相同的接口以便任何时候都能替代真实对象。同时还可以附加另外的操作。
在上图中:
IProxy 是真实角色
Proxy 是抽象角色
ProxyStatic 和 ProxyDynamic 都是代理角色。
静态代理:
/*
* 文 件 名: ProxyStatic.java
* 修 改 人: cKF61853
* 修改时间: 2012-12-12
*/
package cn.fareast.proxy;
import cn.fareast.proxy.iface.IProxy;
/**
* 静态代理实现(静态代理实现类)
*
* @author cKF61853
*/
public class ProxyStatic implements IProxy
{
//代理接口
IProxy proxy;
/**
* 构造静态代理构造函数
* 初始化被代理对象
*/
public ProxyStatic()
{
this.proxy = new Proxy();
}
/**
* 构造静态代理构造函数
* 初始化可接收被代理对象
*/
public ProxyStatic(IProxy proxy)
{
this.proxy = proxy;
}
/**
* 代理方法
*/
@Override
public void talk()
{
System.out.println("This is a static proxy");
this.proxy.talk();
}
}
动态代理:
/*
* 文 件 名: ProxyDynamic.java
* 修 改 人: cKF61853
* 修改时间: 2012-12-12
*/
package cn.fareast.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 动态代理实现(动态代理对象)
*
* @author cKF61853
*/
public class ProxyDynamic implements InvocationHandler
{
/**
* 被代理目标对象
*/
private Object target;
/**
* 创建被代理对象
*/
public Object crateProxy(Object target)
{
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
/**
* 动态代理方法
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
Object result = null;
System.out.println("This is a dynamic proxy.");
result = method.invoke(this.target, args);
return result;
}
}
main 方法
/*
* 文 件 名: ProxyMain.java
* 修 改 人: cKF61853
* 修改时间: 2012-12-12
*/
package cn.fareast.proxy;
import cn.fareast.proxy.iface.IProxy;
/**
* 代理测试类
*
* @author cKF61853
*/
public class ProxyMain
{
/**
* 静态代理方法测试
*/
public void staticProxy()
{
ProxyStatic proxyStatic = new ProxyStatic();
proxyStatic.talk();
}
/**
* 动态代理方法测试
*/
public void dynamicProxy()
{
ProxyDynamic proxyDynamic = new ProxyDynamic();
IProxy iproxy = (IProxy) proxyDynamic.crateProxy(new Proxy());
iproxy.talk();
}
public static void main(String[] args)
{
ProxyMain main = new ProxyMain();
main.staticProxy();
main.dynamicProxy();
}
}
控制台输出
This is a static proxyI can speak, because I'm a person.
This is a dynamic proxy.
I can speak, because I'm a person.