定义
为其他对象提供一种代理以控制对这个对象的访问
使用场景
当无法或不想直接访问某个对象或者访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口
关键点
一个抽象角色—声明具体对象和代理对象共同的接口方法为抽象类或者接口,被访问对象和代理对象均实现该方法
一个具体对象角色—被委托对象或被代理对象,执行具体的业务逻辑方法
一个代理对象—委托类或代理类,持有被委托(被代理)对象引用,通过在其所实现的抽象中调用被委托对象方法保证客户端的透明化
实现
/**
* 抽象角色—声明被代理对象和代理对象需要实现的方法
*/
public interface ILawsuit {
/**
* 提交起诉
*/
void submit();
/**
* 进行举证
*/
void burden();
/**
* 进行辩护
*/
void defend();
/**
* 诉讼完成
*/
void finish();
}
/**
* 具体角色—被代理对象
*/
public class LBJFAN implements ILawsuit {
@Override
public void submit() {
Log.i(getClass().getSimpleName(), "LBJFAN_上诉");
}
@Override
public void burden() {
Log.i(getClass().getSimpleName(), "LBJFAN_举证");
}
@Override
public void defend() {
Log.i(getClass().getSimpleName(), "LBJFAN_辩护");
}
@Override
public void finish() {
Log.i(getClass().getSimpleName(), "LBJFAN_诉讼完成");
}
}
/**
* 代理角色—持有被代理对象引用
*/
public class LayerProxy implements ILawsuit {
private ILawsuit lawsuit;
public LayerProxy(ILawsuit lawsuit) {
this.lawsuit = lawsuit;
}
@Override
public void submit() {
lawsuit.submit();
}
@Override
public void burden() {
lawsuit.burden();
}
@Override
public void defend() {
lawsuit.defend();
}
@Override
public void finish() {
lawsuit.finish();
}
}
使用
//使用
ILawsuit lbjfan = new LBJFAN();
LayerProxy layerProxy = new LayerProxy(lbjfan);
layerProxy.submit();
layerProxy.burden();
layerProxy.defend();
layerProxy.finish();
在上面的例子中,通过代理对象持有一个抽象被代理对象达到依赖抽象的目的,当然我们也可以通过不同的具体代理对象代理相应的具体被代理对象。此外上面 的代码在运行前,代理类的class编译文件就已经存在,我们称之为静态代理,而通过反射机制动态的生成代理者的对象,也就是说在code阶段根本就不知道需要代理谁,只有在执行阶段才知道,这种方式称之为动态代理。
动态代理需要实现系统提供的InvocationHandler,并重写其调用方法invoke
/**
* 动态代理
*/
public class DynamicProxy implements InvocationHandler {
/**
* 被代理对象的引用
*/
private Object object;
public DynamicProxy(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = method.invoke(object, args);
return obj;
}
}
使用
//构造一个被代理对象
ILawsuit lbjfan = new LBJFAN();
//构造一个动态代理对象
DynamicProxy proxy = new DynamicProxy(lbjfan);
//获取被代理对象的ClassLoader
ClassLoader loader = lbjfan.getClass().getClassLoader();
//动态构造一个代理
ILawsuit lawsuit = (ILawsuit) Proxy.newProxyInstance(loader, new Class[]{ILawsuit.class}, proxy);
//访问被代理对象
lawsuit.submit();
lawsuit.burden();
lawsuit.defend();
lawsuit.finish();
小结
优点
代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用,且对客户端和目标对象进行了解耦,扩展性极高。
缺点
类增加(可忽略不计)