什麼是代理模式
在公司上班,每月都要繳納社保,你從來沒有自己去社保中心繳納過,都是由公司人力部門代你繳納,人力小姐姐就是你的代理人,幫你做了這件事情。
火車票由鐵路局印售,全國各地都有火車票代售點,你去最近的代售點就能買到你想要的車票,不用跑去鐵路局,代售點就是鐵路局的代理人,負責代理售賣火車票。
我具備做一件事情的能力,但是我又不想親自做,就招個代理幫我做事情,這就是代理模式。
代理模式有兩個角色:代理者、被代理者。代理者幫被代理者做事情,被代理者是幕後的老闆,代理者只是個跑腿的。
代理模式應用到編程中,又被分爲兩個概念:靜態代理、動態代理。兩者區別:
- 靜態代理:系統運行前,代理類就存在
- 動態代理:系統運行前,代理類不存在,運行後動態生成代理類
模式設計與實現
因爲代理模式只涉及兩個核心角色:代理者、被代理者。
所以模式設計相對簡單,不管怎麼設計,只要能完成代理任務,就都可以稱之爲代理模式。
具體到編程語言的實現,就各有各的方法,這裏以Java
語言爲例,講述代理模式的實現方法。
靜態代理
原則是代理類事先就存在,那就只能自己手寫代理類了。
因此,靜態代理的Java
代碼實現,大概是這樣的:
public interface Subject {
void request();
}
// 被代理類
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("do something");
}
}
// 代理類
public class RealSubjectProxy implements Subject {
private RealSubject realSubject = new RealSubject();
@Override
public void request() {
System.out.println("proxy do something");
realSubject.request();
System.out.println("proxy do something");
}
}
前面說,代理者是幫被代理者做事情的,但是,看代碼邏輯,雖然經過代理類,可最後感覺還是要勞煩被代理者自己把事情做了。
不知道讀者有沒有類似的感覺,反正我以前有過。後來想明白了,總結出代理模式的另一個特點:
代理者幫助被代理者做事情,可以添加一些輔助任務,但是核心任務必須通過被代理者去完成。
什麼意思呢?就是說:
- 代售點可以幫鐵路局收錢記賬,但是賣票的核心任務還是由鐵路局控制的
- 人力小姐姐可以幫你計算社保並代繳,但是核心的社保信息還得是你的
動態代理
JDK
本身就提供有動態代理的機制,通過反射等手段,在系統運行的時候,動態生成代理類,還是比較方便的。
大概的代碼如下:
public interface Subject {
void request();
}
// 被代理類
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("do something");
}
}
// 這個類的主要內容是"代理任務的執行邏輯",它不是代理類
public class ProxyLogic implements InvocationHandler {
private Object realSubject;// 真實主題
public RealSubjectDynamicProxy(Object realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy do something");
Object invoke = method.invoke(realSubject, args);
System.out.println("proxy do something");
return invoke;
}
}
// 測試方法,展示如果生成代理類
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
// 代理類:動態生成的
Subject proxy = (Subject) Proxy.newProxyInstance(
RealSubject.class.getClassLoader(),
new Class[]{Subject.class},
new ProxyLogic(realSubject)
);
}
動態代理不像靜態代理那樣,要把整個代理類都寫一遍,但是核心的代理邏輯還是要寫的。
爲什麼這麼寫,不是本文的重點,有興趣的可以去了解java.lang.reflect.Proxy
的實現邏輯。
總結
- 如果單純只說設計模式,就只有“代理模式”這一說,具體到編程語言的實現,纔有靜態代理、動態代理這兩種區分
- 靜態代理寫法簡單,編碼靈活度高,例如代理類方法名、被代理類哪些方法需要代理,都是可以自由選擇的
- 動態代理寫法稍微複雜,編碼靈活度不高,但是編碼規範度較高。如果被代理類方法較多,代理邏輯又是相同的,就適合使用動態代理,可以大幅度減少代碼量