定義
爲其他對象提供一種代理以控制對這個對象的訪問
使用場景
當無法或不想直接訪問某個對象或者訪問某個對象存在困難時可以通過一個代理對象來間接訪問,爲了保證客戶端使用的透明性,委託對象與代理對象需要實現相同的接口
關鍵點
一個抽象角色—聲明具體對象和代理對象共同的接口方法爲抽象類或者接口,被訪問對象和代理對象均實現該方法
一個具體對象角色—被委託對象或被代理對象,執行具體的業務邏輯方法
一個代理對象—委託類或代理類,持有被委託(被代理)對象引用,通過在其所實現的抽象中調用被委託對象方法保證客戶端的透明化
實現
/**
* 抽象角色—聲明被代理對象和代理對象需要實現的方法
*/
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();
小結
優點
代理對象可以在客戶端和目標對象之間起到中介的作用,這樣起到了中介的作用和保護了目標對象的作用,且對客戶端和目標對象進行了解耦,擴展性極高。
缺點
類增加(可忽略不計)