前言
代理模式也被稱爲委託模式,它是結構型設計模式的一種。在現實生活中我們用到類似代理模式的場景有很多,比如代理上網、打官司等。
定義
爲其他對象提供一種代理以控制對這個對象的訪問。
角色
- Subject:抽象主題類,聲明真實主題與代理的共同接口方法。
- RealSubject:真實主題類,代理類所代表的真實主題。客戶端通過代理類間接地調用真實主題類的方法。
- Proxy:代理類,持有對真實主題類的引用,在其所實現的接口方法中調用真實主題類中相應的接口方法執行。
- client:客戶端類。
類型
從編碼角度分類
- 靜態代理
- 動態代理
從適用範圍分類
-
遠程代理:爲一個對象在不同的地址空間提供局部代表,這樣系統可以將
Server
部分的實現隱藏。 - 虛擬代理:使用一個代理對象表示一個十分耗資源的對象並在真正需要是才創建。
- 安全代理:用來控制真實對象訪問的權限。一般用於真實對象有不同的訪問權限時。
- 智能指引:當調用真實的對象時,代理處理另外一些事,比如計算機真實對象的引用計數,當該對象沒有引用時,可以自動釋放它;或者訪問一個實際對象時,檢查是否已經能夠鎖定它,以確保其他對象不能改變它。
靜態代理模式的簡單實現
場景描述
我多年沒有回哈爾濱了,很想念哈爾濱的秋林紅腸味道。但是本人因爲工作一直很忙抽不開身,不能夠親自回哈爾濱購買,於是就拜託在哈爾濱的朋友幫我購買秋林紅腸。
-
抽象主題類:抽象主題類具有真實主題類和代理的共同接口方法
buy
public interface IShop {
void buy();
}
-
真實主題類:這個購買者
Giants
就是我,實現了IShop
接口提供的buy
方法。
public class Giants implements IShop {
@Override
public void buy() {
System.out.println("購買");
}
}
-
代理類:我找的代理類同樣也要實現
IShop
接口,並且要持有被代理者,在buy
方法中調用了被代理者的buy
方法。
public class Purchasing implements IShop {
private IShop mShop;
public Purchasing(IShop shop) {
this.mShop = shop;
}
@Override
public void buy() {
mShop.buy();
}
}
- 客戶端類:客戶端類的代碼就是包含了真實主題類(被代理者),最終調用的都是真實主題類(被代理者)實現的方法。
public class Client {
public static void main(String[] args) {
IShop giants = new Giants();
IShop purchasing = new Purchasing(giants);
purchasing.buy();
}
}
動態代理模式的簡單實現
場景描述
上面的例子是一個靜態的代理,在代碼運行前已經存在了代理類的
class
編譯文件;而動態代理則是在帶來運行時通過反射來動態地生成代理類的對象,並確定到底代理誰。我們在編碼階段無需知道代理誰,代理誰將會在代碼運行時覺定。
- 創建動態代理類
/**
* 實現Java提供的動態代理接口 InvocationHandler ,實現該接口需要重寫 invoke 方法
*/
public class DynamicPurchasing implements InvocationHandler {
private Object obj;
public DynamicPurchasing(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(obj, args);
if(method.getName().equals("buy")){
System.out.println("Giants在買買買");
}
return result;
}
}
- 修改客戶端類代碼如下:調用
Proxy.newProxyInstance
來生成動態代理類,調用purchasing
的buy
方法會調用mDynamicPurchasing
的invoke
方法。
public class Client {
public static void main(String[] args) {
//創建 Giants
IShop giants = new Giants();
//創建動態代理
DynamicPurchasing mDynamicPurchasing = new DynamicPurchasing(giants);
//創建 giants 的 ClassLoader
ClassLoader loader = giants.getClass().getClassLoader();
//動態創建代理類
IShop purchasing = (IShop) Proxy.newProxyInstance(loader, new Class[] {IShop.class}, mDynamicPurchasing);
purchasing.buy();
}
}
優點
- 真實主題類就是實現實際的業務邏輯,不用關心其他非本職工作。
- 真實主題類隨時都會發生變化;但是因爲它實現了公共的接口,所以代理類可以不做任何修改就能夠使用。