[設計模式] 結構型:代理模式,靜態代理、動態代理(Proxy Pattern)

什麼是代理模式

在公司上班,每月都要繳納社保,你從來沒有自己去社保中心繳納過,都是由公司人力部門代你繳納,人力小姐姐就是你的代理人,幫你做了這件事情。

火車票由鐵路局印售,全國各地都有火車票代售點,你去最近的代售點就能買到你想要的車票,不用跑去鐵路局,代售點就是鐵路局的代理人,負責代理售賣火車票。

我具備做一件事情的能力,但是我又不想親自做,就招個代理幫我做事情,這就是代理模式。

代理模式有兩個角色:代理者、被代理者。代理者幫被代理者做事情,被代理者是幕後的老闆,代理者只是個跑腿的。

代理模式應用到編程中,又被分爲兩個概念:靜態代理、動態代理。兩者區別:

  1. 靜態代理:系統運行前,代理類就存在
  2. 動態代理:系統運行前,代理類不存在,運行後動態生成代理類

模式設計與實現

因爲代理模式只涉及兩個核心角色:代理者、被代理者。

所以模式設計相對簡單,不管怎麼設計,只要能完成代理任務,就都可以稱之爲代理模式。

具體到編程語言的實現,就各有各的方法,這裏以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");
    }
}

前面說,代理者是幫被代理者做事情的,但是,看代碼邏輯,雖然經過代理類,可最後感覺還是要勞煩被代理者自己把事情做了。

不知道讀者有沒有類似的感覺,反正我以前有過。後來想明白了,總結出代理模式的另一個特點:

代理者幫助被代理者做事情,可以添加一些輔助任務,但是核心任務必須通過被代理者去完成。

什麼意思呢?就是說:

  1. 代售點可以幫鐵路局收錢記賬,但是賣票的核心任務還是由鐵路局控制的
  2. 人力小姐姐可以幫你計算社保並代繳,但是核心的社保信息還得是你的

動態代理

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的實現邏輯。

總結

  1. 如果單純只說設計模式,就只有“代理模式”這一說,具體到編程語言的實現,纔有靜態代理、動態代理這兩種區分
  2. 靜態代理寫法簡單,編碼靈活度高,例如代理類方法名、被代理類哪些方法需要代理,都是可以自由選擇的
  3. 動態代理寫法稍微複雜,編碼靈活度不高,但是編碼規範度較高。如果被代理類方法較多,代理邏輯又是相同的,就適合使用動態代理,可以大幅度減少代碼量
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章