定義
- 什麼是代理模式? 代理模式就是你不直接和對方打交道,而是讓第三方跟他打交道,你只從第三方那裏獲取資源。在代碼世界裏,就是,我直接訪問代理類Proxy ,這個類裏面有你想要的資源,它負責從資源方獲取資源。
分類
靜態代理
沒說的,先上代碼…
- 資源接口:這個是目標資源
public interface Sourceable {
public void method();
}
- 這個是資源接口
public class Source implements Sourceable {
public void method() {
System.out.println("the original method!");
}
}
- 這個就是代理了
public class Proxy implements Sourceable {
private Source source;
public Proxy(){
super();
this.source = new Source();
}
public void method() {
//新增的處理,個性化處理
before();
source.method();
atfer();
}
private void atfer() {
System.out.println("after proxy!");
}
private void before() {
System.out.println("before proxy!");
}
}
- 用方法去調用
public class Test {
public static void main(String[] args) {
Sourceable source = new Proxy();
source.method();
}
}
- 輸出結果:
before proxy!
the original method!
after proxy!
從上面的過程可以看出,所謂的代理就是他提前和資源方取得了聯繫,獲取到它的資源,然後再增加了一些個性化的before atfer 方法以方便根據業務的不同來調用。這樣一來就確定了他的優點: 擴展原功能,不侵入原代碼。但是如果要是有10個以上的method 那麼我拓展起來可就麻煩了。正是因爲這個缺點纔出現了第二種代理模式:動態代理。
動態代理
什麼是動態代理?
- 當想要給實現了某個接口的類中的方法,加一些額外的處理。比如說加日誌,加事務等。可以給這個類創建一個代理,故名思議就是創建一個新的類,這個類不僅包含原來類方法的功能,而且還在原來的基礎上添加了額外處理的新類。這個代理類並不是定義好的,是動態生成的。具有解耦意義,靈活,擴展性強。
一直以爲java中概念性的東西太過於術語化,本來一個簡單的問題非要說的很高大上,其實我們來看下代碼就知道了,千萬不要對這些術語弄蒙了!
動態代理優點
- 動態代理實現了只需要將被代理對象作爲參數傳入代理類就可以獲取代理類對象,從而實現類代理,具有較強的靈活性。
- 動態代理的服務內容不需要像靜態代理一樣寫在每個代碼塊中,只需要寫在invoke()方法中即可,降低了代碼的冗餘度。
和靜態代理一樣,動態代理也得先寫個資源類(就這一點,還是要寫接口,所以兩種代理模式挺麻煩的)。
public interface Colorable {
public void value();
}
public class RedColor implements Colorable{
public void value() {
System.out.println("--------------red-------------");
}
}
這個是代理實現類
package com.heigherjavatest.designpattern.proxy.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
* 【Author】 技術支持史
* 【Time】2020年5月24日 下午4:17:47
* 【Function】
*/
public class ColorableAOProxy implements InvocationHandler {
private Colorable colorable;
private Colorable proxy;
public ColorableAOProxy(Colorable colorable) {
this.colorable = colorable;
this.proxy = (Colorable) Proxy.newProxyInstance(
Colorable.class.getClassLoader(),
new Class<?>[] { Colorable.class }, this);
}
public Colorable getProxy() {
return proxy;
}
/**
*proxy:代表動態代理對象
*method:代表正在執行的方法
*args:代表調用目標方法時傳入的實參
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
ToolUtility tool = new ToolUtility();
tool.method();
String methodName = method.getName();
System.out.println("===========starting invoke function:" + methodName
+ "==========");
Object result = method.invoke(colorable, args);
System.out.println("=========== invoke function:" + methodName
+ " success==========");
return result;
}
}
其中那個ToolUtility 是我寫的另一個類:
public class ToolUtility {
public void method(){
System.out.println("運行了ToolUtility");
}
}
然後開始測試!
public class Main {
public static void main(String[] args) {
Colorable proxy = new ColorableAOProxy(new RedColor()).getProxy();
proxy.value();
}
}
輸出:
所以,動態代理的好處就在於它拓展的時候是在invoke 方法裏面的,因爲它實現了 InvocationHandler 接口,不是實現了資源類,這樣就避免了大量的代碼冗餘,更適合大型項目中使用。拓展方法的任務交給了invoke 不必擔心Colorable 裏面的抽象方法。
總結
無論是靜態代理還是動態代理,寫的時候讀要寫接口和實現接口,總體上代碼量還是很多的,所以在現實案例中,我們經常在調試中看到很多代理對象,都被封裝起來了。其實不止是代理模式,很多模式都做了封裝,我們只需要進行調用即可,我們不用抱有太大壓力去學習,只需要理解其中的原理即可。
- 歡迎大家和我一起討論有關JAVA設計模式的問題,共同成長。