代理模式就是给某一个对象提供一个代理对象,并由代理对象控制对源对象的引用。就是一个人或者一个机构代替另一个人或者另一个机构去采取一些行动。代理模式中的代理者就好比中介机构,它提供了对被代理对象的一切事物。
代理模式与适配器模式和装饰器模式相似,它们之间的区别是:
Ø 适配器模式是将一个类A转换成另一个类B。
Ø 装饰器模式是为一个类A增加新的功能,从而变成类B。
Ø 代理模式是为一个类A转换操作类B。
它们三者的限制条件层层递进,递进关系
代理模式
|
装 饰 器 模 式
|
适 配 器 模 式
// 被代理对象的接口Sourcable:声明了代理对象和代理者的共同接口。
public interface Sourcable {
void opteration(); //同共操作接口
}
//代理对象Source:定义真实的对象
public class Source implements Sourcable{
public void opteration(){
System.out.println("do the real opteration mehtod....");
}
}
public class Proxy implements Sourcable{
private Source realSubject; // 以真实角色作为代理角色的属性
public void opteration(){ // 该方法封装了真实对象的request方法
before(); //代理前后执行一些前后方法
if ( realSubject == null ) {
realSubject = new Source();
}
realSubject.opteration();
after();
}
public void before() {
System.out.println("代理前");
}
public void after() {
System.out.println("代理后");
}
}
public class Client {
public static void main(String[] args){
Sourcable sour=new Proxy();
sour.opteration();
}
}
代理模式中的“代理”要想实现代理任务,就必须与被代理的“对象”使用共同的接口。所以自然而然你会想到在Java中使用一个抽象类或者接口(推荐)来实现这个共同的接口。于是代理模式就有3个角色组成。
Ø 被代理对象的接口Sourcable:声明了代理对象和代理者的共同接口。
Ø 被代理对象Source:定义真实的对象。
Ø 代理者Proxy:内部包含对代理对象的引用,并且提供与代理对象角色相同的接口
从程序的输出可以看出,通过Proxy不仅实现了对Source的调用,还实现了自身的功能,这与装饰器模式很相似,不同的是它们的关注点不同:装饰器模式关注于扩展功能,而代理模式关注于如何调用。
通过上面的代码可以看出,代理主题ProxyObject类并没有实现我们定义的SellInterface借口,
而是实现了java的InvocationHandler接口,这样就把代理主题角色和我们的业务代码分离开来,使代理对象能通用于其他接口.
其实InvocationHandler接口就是一种拦截机制,当系统中有了代理对象以后,对原对象(真实主题)方法的调用,都会转由InvocationHandler接口来处理,并把方法信息以参数的形式传递给invoke方法,这样,我们就可以在invoke方法中拦截原对象的调用,并通过反射机制来动态调用原对象的方法.这好象也是spring aop编程的基础吧
接着,用代理模式实现一个超级简单的aop拦截机制
这个例子可以拦截我们指定的函数,并在拦截前后根据需要进行处理
Java代码
/**
*切面接口,通过实现这个接口,我们可以对指定函数在调用前后进行处理
*/
public interface AopInterface {
public void before(Object obj);//调用的处理
public void end(Object obj);//调用后的处理
}
这个是实现了AopInterface 接口,在这里我们实现了我们的处理逻辑
Java代码
public class AopInterfaceImp implements AopInterface{
public void before(Object obj) {
System.out.println("调用前拦截");
}
public void end(Object obj) {
System.out.println("调用调用后处理");
}
}
接着是代理类
Java代码
public class PeoxyObject implements InvocationHandler {
private AopInterface aop;//定义了切入时调用的方法
private Object proxy_obj;
private String methodName;//指定要切入的方法名
PeoxyObject(){}
public Object factory(Object obj){
proxy_obj = obj;
Class cls = obj.getClass();
return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(this.aop == null)throw new NullPointerException("aop is null");
if(method == null)throw new NullPointerException("method is null");
Object o;
//如果指定了要拦截方法名,并且调用的方法和指定的方法名相同,则进行拦截处理
//否则当正常方法处理
if(methodName != null && method.toString().indexOf(methodName) != -1){
aop.before(proxy_obj);//指定方法调用前的处理
o = method.invoke(proxy_obj, args);
aop.end(proxy_obj);//指定方法调用后的处理
}else{
//没有指定的方法,以正常方法调用
o = method.invoke(proxy_obj, args);
}
return o;
}
public AopInterface getAop() {
return aop;
}
public void setAop(AopInterface aop) {
this.aop = aop;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
}
这里定义一个用来测试用的类
Java代码
public interface SubInterface {
public void add(String value1,String value2);
public void acc(String value1);
}
public class ImpObject implements SubInterface{
public void add(String value1,String value2) {
System.out.println("ImpObject add(String value1,String value2)");
}
public void acc(String value1){
System.out.println("ImpObject acc(String value1)");
}
}
这里是测试代码
Java代码
public static void main(String agr[]){
PeoxyObject po = new PeoxyObject();
po.setAop(new AopInterfaceImp());//我们实现的拦截处理对象
po.setMethodName("acc");//指定要拦截的函数
SubInterface si = (SubInterface)po.factory(new ImpObject());
//因为add方法不是我们指定的拦截函数,AopInterfaceImp是不会被执行
si.add("tt","dd");
//acc是我们指定的拦截方法,所以调用acc的前后会先执行AopInterfaceImp
//对象的两个方法
si.acc("tt");
}
通过上面可以看出,拦截机制是代理模式的重要使用方式之一,
除了拦截,代理模式还常用于资源加载,当我们要加载的资源很大时,我们可以让真实主题角色在后台加载资源,让代理主题角色负责处理前台的等待提示信息.
还有就是授权机制,通过代理能拦截真实主题的能力,来控制真实主题的访问权限