代理模式是对象的结构模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。
代理模式的结构
所谓代理,就是一个人或者机构代表另一个人或者机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理模式类图如下:
在代理模式中的角色:
● 抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。
● 目标对象角色:定义了代理对象所代表的目标对象。
● 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。
源代码
抽象对象角色
package com.bankht.Proxy;
/**
* @author: 特种兵—AK47
* @创建时间:2012-6-26 上午10:40:16
*
* @类说明 :抽象对象角色
*/
public abstract class AbstractObject {
// 操作
public abstract void operation();
}
目标对象角色
package com.bankht.Proxy;
/**
* @author: 特种兵—AK47
* @创建时间:2012-6-26 上午10:40:46
*
* @类说明 :目标对象角色
*/
public class RealObject extends AbstractObject {
@Override
public void operation() {
// 一些操作
System.out.println("一些操作");
}
}
代理对象角色
package com.bankht.Proxy;
/**
* @author: 特种兵—AK47
* @创建时间:2012-6-26 上午10:41:06
*
* @类说明 :代理对象角色
*/
public class ProxyObject extends AbstractObject {
RealObject realObject = new RealObject();
@Override
public void operation() {
// 调用目标对象之前可以做相关操作
System.out.println("before");
realObject.operation();
// 调用目标对象之后可以做相关操作
System.out.println("after");
}
}
客户端
package com.bankht.Proxy;
/**
* @author: 特种兵—AK47
* @创建时间:2012-6-26 上午10:41:32
*
* @类说明 :客户端:代理对象将客户端的调用委派给目标对象,在调用目标对象的方法之前跟之后都可以执行特定的操作。
*/
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractObject obj = new ProxyObject();
obj.operation();
}
}
运行一下:
before
一些操作
after
从上面的例子可以看出代理对象将客户端的调用委派给目标对象,在调用目标对象的方法之前跟之后都可以执行特定的操作。
采用Java代理模式,代理类通过调用委托类对象的方法,来提供特定的服务。委托类需要实现一个业务接口,代理类返回委托类的实例接口对象。
按照代理类的创建时期,可以分为:静态代理和动态代理。
所谓静态代理: 指程序员创建好代理类,编译时直接生成代理类的字节码文件。
所谓动态代理: 在程序运行时,通过反射机制动态生成代理类。
静态代理类的特点: 代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样就出现了大量的代码重复。而且代理类只能为特定的接口(Service)服务。
动态代理: 代理类需要实现InvocationHandler接口。
使用场合举例: 如果需要委托类处理某一业务,那么我们就可以先在代理类中,对客户的权限、各类信息先做判断,如果不满足某一特定条件,则将其拦截下来,不让其代理。
上代码:
package com.bankht.Proxy;
/**
* @author: 特种兵—AK47
* @创建时间:2012-6-27 上午11:11:47
*
* @类说明 :
*/
public interface Service {
/**
* 查询日期
*/
public String queryDate();
/**
* 计算两个整数之差
*/
public int sub(int a, int b);
}
package com.bankht.Proxy;
import java.util.Date;
/**
* @author: 特种兵—AK47
* @创建时间:2012-6-27 上午11:12:30
*
* @类说明 :
*/
public class ServiceImpl implements Service {
@Override
public String queryDate() {
return new Date().toString();
}
@Override
public int sub(int a, int b) {
return a - b;
}
public String ownMethod() {
System.out.println("It's my own method");
return "admin";
}
}
package com.bankht.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author: 特种兵—AK47
* @创建时间:2012-6-27 上午11:07:15
*
* @类说明 :
*/
public class ServiceProxy implements InvocationHandler {
private Object target;
public ServiceProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
if (!(target instanceof ServiceImpl)) {
System.out.println("不能代理该对象");
return result;
} else if (!((ServiceImpl) target).ownMethod().equals("admin")) {
System.out.println("权限不够");
return result;
}
result = method.invoke(target, args);
return result;
}
/**
* @param target
* @return 返回委托类接口的实例对象
*/
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
package com.bankht.Proxy;
/**
* @author: 特种兵—AK47
* @创建时间:2012-6-27 上午11:10:10
*
* @类说明 :
*/
public class ServiceTest {
public static void main(String[] args) {
// 创建委托类实例,即被代理的类对象
ServiceImpl target = new ServiceImpl();
// 创建动态代理类
ServiceProxy proxy = new ServiceProxy(target);
Service service = (Service) proxy.getProxyInstance();
String date = service.queryDate();
System.out.println(date);
int result = service.sub(10, 20);
System.out.println("10-20 = " + result);
}
}
运行一下:
It's my own method
Wed Jun 27 11:27:13 CST 2012
It's my own method
10-20 = -10
如果将
ServiceImpl.java 中ownMethod()方法
return "admin";
改为:
return "ak47";
运行一下:
It's my own method
权限不够
null
It's my own method
权限不够
Exception in thread "main" java.lang.NullPointerException
at $Proxy0.sub(Unknown Source)
at com.bankht.Proxy.ServiceTest.main(ServiceTest.java:18)