1. 程式人生 > >設計模式——代理模式(Proxy)

設計模式——代理模式(Proxy)

定義

為其他物件提供一種代理,以控制對這個物件的訪問。代理物件在客戶端和目標物件之間起到中介的作用。(結構型)

如果不知道代理模式,可能大家對代理伺服器都不叫熟悉。代替伺服器代替請求者去發一起對另一個伺服器的請求,他相當於請求的中間人。為什麼要通過這個代理呢,那是因為客戶端直接去訪問伺服器會被拒絕(防火牆遮蔽),而代理伺服器則可以直接訪問伺服器。這裡有兩種應用場景,一種是國內的FQ了(靜態代理),另一種是hacker想掩蓋自己的ip時,往往會通過多層代理伺服器進行訪問/或者不停的切換代理(動態代理,《who am i》電影裡面男主就是通過代理去和另外一個haacker通訊,而且所用的代理一直在變防止被追蹤到)

模板

抽象角色(Subject)
通過介面或抽象類宣告真實角色實現的業務方法。

代理角色(RealSubject)
實現抽象角色,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並可以附加自己的操作

真實角色(Proxy)
實現抽象角色,定義真實角色所要實現的業務邏輯,供代理角色呼叫

例項

a) 靜態代理

Main中去呼叫ProxyPrinter中的print方法而不需要關心被代理類(Printer),由於程式碼比較簡單,這裡就不具體展開。

b) 動態代理
這裡列舉了一個可以將任何方法的執行放在指定執行緒(提前建立好的UI執行緒和後臺執行緒)的動態代理實現,具體如下:

假如一個有一個寫檔案的操作類如下:

public class FileWriter {

    private void writeBytesToFile(String fileName, Byte[] bytes) {
       // 將二進位制檔案寫入到 檔案中
    }
}

做過前端開發的應該都知道寫檔案是一個耗時操作,不能在主執行緒中執行,那我們現在怎麼辦?

FileWriter fileWriter = new FileWriter();
FileWriter proxyWriter = ObjectThreadProxy.back(fileWriter, FileWriter.class);
proxyWriter.writeBytesToFile("TestFile.txt", xxxx);

上述程式碼通過前面講的ObjectThreadProxy工具類就可以將被代理的物件轉換成proxyWriter,接下來呼叫proxyWriter的任何方法都會執行在子執行緒中。這是如何做到的,具體看一下back方法及ThreadInvocationHandler就知道了:

// back 方法中建立代理類
ThreadInvocationHandler handler = new ThreadInvocationHandler(realObj, syncMode);
Object proxyObj = Proxy.newProxyInstance(class.getClassLoader(), new Class[]{class}, handler);
return proxyObj;


// ThreadInvocationHandler 中invoke方法關鍵程式碼如下:
public Object invoke(Object proxy, final Method method, final Object[] args) {
    switch(mode) {
        case BACK:
            // 在子執行緒執行方法
            method.invoke(readObject, args);
            break;
        case MAIN:
            // 在主執行緒中執行
            break;
}

優點

1.代理模式能將代理物件與真實物件被呼叫的目標物件分離,一定程度上降低了系統的耦合度,擴充套件性好。
2.保護目標物件。
3.增強目標物件。

缺點

  1. 建立多個類,增加程式碼閱讀複雜性(所有設計模式通病)
  2. clone方法只是淺拷貝,除五種基礎型別之外型別都只是簡單的指向引用,不會重新建立成員變數,如需實現需要自定義clone方法。
  3. 通過clone方法不會呼叫類的建構函式,部分場景(在建構函式中做一些初始化操作的)需要做額外的處理

適用場景

1.保護目標物件
2.增強目標物件

與裝飾模式的區別

對物件的作用
裝飾者:動態的新增或組合物件的行為,在不改變介面的前提下,動態擴充套件物件的功能
代理模式:為其他物件提供一種代理以控制對這個物件的訪問,在不改變介面的前提下,控制物件的訪問

如何使用該物件
裝飾者:通常將原始物件作為引數傳遞給Decorator的建構函式。
代理模式:代理類中建立一個真實物件的例項
注: 其實代理模式也可以作為引數傳遞,這裡是網上很多地方的寫法,自己並不贊同。

模式的核心
裝飾者:強調的是增強自身,在被裝飾之後你能夠在被增強的類上使用增強後的功能。增強後你還是你,只不過能力更強了而已
代理模式:強調要讓別人去做一些本身和你業務沒有太多關係的職責(記錄日誌,設定快取,遠端代理負責網路通訊的一些細節),代理模式是為了實現對物件的控制,因為被代理的物件往往難以直接獲得或者其內部不想暴露出來

其它例項:

待補