Proxy模式(代理[延遲]模式)

來源:互聯網
上載者:User

標籤:編輯器   access   win   遠程   技術   時間   handler   圖形   ...   

Proxy??

Proxy是“代理人”的意思,它指的是代替別人進行工作的人。代理實際上就是使用委託的機制,在代理的過程中你可以做點其他的事情,然後再來執行被代理對象的代碼。

  • 知識儲備

1.什麼時候使用:

GoF書(請參見附錄E[GoF])在講解Proxy模式時,使用了一個可以在文本中嵌入繪圖物件(例片等)的文字編輯器作為例子。為了產生這些繪圖物件,需要讀取圖片檔案,這很耗費時間。因此如果在開啟文檔時就產生有所的繪圖物件,就會導致文檔開啟時間過長。所以,最好是當使用者瀏覽至文本中各個繪圖物件時,再去產生它們的執行個體。這時,Proxy模式就有了用武之地。

2.有那些代理:

  • Virtual Proxy(虛擬代理)Virtual Proxy就是本章中學習的Proxy模式。只有當真正需要執行個體時,它才產生和初始化執行個體。
  • Remote Proxy(遠程代理)Remote Proxy可以讓我們完全不必在意RealSubject角色是否在遠程網路上,可以如同它在自己身邊一樣(透明性地)調用它的 方法。Java的RMI(RemoteMethodInvocation:遠程方法調用)就相當於Remote Proxy。
  • Access Proxy Access Proxy 用於在調用RealSubject角色的功能時設定訪問限制。例如,這種代理可以只允許指定的使用者調用方法,而當其他使用者調用方法時則報錯。

  • 靜態代理
    1.使用委託機制代理人只代理他能解決的問題。當遇到他不能解決的問題時,還是會“轉交”給本人去解決。
    這裡的“轉交”就是在本書中多次提到過的“委託”。從PrinterProxy類的print方法中調用real.print方法正是這種“委託”的體現。

  1. 為了實現PrinterProxy類可以從printer類中分離出來作為獨立的組件使用,而且只要是實現了Printable介面的類都可以扮演Proxy的角色。需要使用反射執行個體
private synchronized void realize(String classname) {    if(real==null){        try {            real = ((Printable) Class.forName(classname).newInstance());        }catch (ClassNotFoundException e){            System.out.println("沒有發現"+classname);        }catch (Exception e){            e.printStackTrace();        }    }}
  • 動態代理

在java的動態代理機制中,有兩個重要的類或介面,一個是 InvocationHandler(Interface)、另一個則是 Proxy(Class),這一個類和介面是實現我們動態代理所必須用到的。首先我們先來看看java的API協助文檔是怎麼樣對這兩個類進行描述的:
InvocationHandler:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每一個動態代理類都必須要實現InvocationHandler這個介面,並且每個代理類的執行個體都關聯到了一個handler,當我們通過代理對象調用一個方法的時候,這個方法的調用就會被轉寄為由InvocationHandler這個介面的 invoke 方法來進行調用。我們來看看
InvocationHandler這個介面的唯一一個方法?invoke?方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable

我們看到這個方法一共接受三個參數,那麼這三個參數分別代表什麼呢?

Object invoke(Object proxy, Method method, Object[] args) throws Throwableproxy:  指代我們所代理的那個真實對象method:  指代的是我們所要調用真實對象的某個方法的Method對象args:  指代的是調用真實對象某個方法時接受的參數
理清職責
  • 實現一個帶名字的印表機
    名字=====》》說明
    Printer || 表示帶名字的印表機的類(本人)
    Printable || Printer和PrinterProxy的共同介面
    PrinterProxy || 表示帶名字的印表機的類(代理人)
    Main ||測試程式行為的類
UML

類圖:

時序圖:

Code
  • Printable
public interface Printable {    // 設定列印名字    void setPrinterName(String name);    // 擷取列印名字    String getPrinterName();    // 顯示文字    void print(String string);}
  • Printer

···
public class Printer implements Printable{
private String name;

public Printer() {    heavyjob("正在產生Printer執行個體");}public Printer(String name) {    this.name = name;    heavyjob("正在產生Printer執行個體("+name+")");}/** * 類比一個高負載任務 * @param string */private void heavyjob(String string) {    System.out.println(string);    for (int i = 0; i < 5; i++) {        try {            Thread.sleep(1000);        }catch (InterruptedException e){            e.printStackTrace();        }        System.out.print(".");    }}@Overridepublic void setPrinterName(String name) {    this.name=name;}@Overridepublic String getPrinterName() {    return name;}@Overridepublic void print(String string) {    System.out.println("==="+name+"===");    System.out.println(string);}

}

···

  • PrinterProxy
public class PrinterProxy implements Printable{    private String name;    private Printer real;    /**     * 不論 setPrinterName 方法和getPrinterName 方法被調用多少次,     * 都不會產生Printer類的執行個體。只有當真正需要本人時,     * 才會產生printer類的執行個體(printerProxy類的調用者完全不知道是否產生了本人,也不用在意是否產生了本人)。     * @param name     */    public PrinterProxy(String name) {        this.name = name;    }    @Override    public synchronized void setPrinterName(String name) {        if(real!=null){            real.setPrinterName(name);        }        this.name=name;    }    @Override    public String getPrinterName() {        return name;    }    @Override    public void print(String string) {            realize();            real.print(string);    }    private synchronized void realize() {        if(real==null) real=new Printer(name);    }}public class MainT {    public static void main(String[] args) {        Printable p=new PrinterProxy("Tom");        System.out.println("現在是"+p.getPrinterName());        p.setPrinterName("Cat");        System.out.println("現在是"+p.getPrinterName());        p.print("我是 Tomcat");    }}
  • 結果:
現在是Tom現在是Cat正在產生Printer執行個體(Cat).....===Cat===我是 Tomcat
動態代理Code
public class Client {    public static void main(String[] args) {        Printable tom = new Printer("Tom");        DynamicProxy proxy = new DynamicProxy(tom);        Printable o = (Printable) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),                tom.getClass().getInterfaces(), proxy);        System.out.println(o.getClass().getName());        System.out.println("現在是"+o.getPrinterName());        o.print("Tomcat");    }}public class DynamicProxy implements InvocationHandler {    private Object object;    public DynamicProxy(Object object) {        this.object = object;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("準備執行");        System.out.println("Method:" + method);        Object o = method.invoke(object, args);        System.out.println("執行完畢");        return o;    }}public interface Printable {    // 設定列印名字    void setPrinterName(String name);    // 擷取列印名字    String getPrinterName();    // 顯示文字    void print(String string);}public class Printer implements Printable{    private String name;    public Printer() {        heavyjob("正在產生Printer執行個體");    }    public Printer(String name) {        this.name = name;        heavyjob("正在產生Printer執行個體("+name+")");    }    /**     * 類比一個高負載任務     * @param string     */    private void heavyjob(String string) {        System.out.println(string);        for (int i = 0; i < 5; i++) {            try {                Thread.sleep(1000);            }catch (InterruptedException e){                e.printStackTrace();            }            System.out.print(".");        }    }    @Override    public void setPrinterName(String name) {        this.name=name;    }    @Override    public String getPrinterName() {        return name;    }    @Override    public void print(String string) {        System.out.println("==="+name+"===");        System.out.println(string);    }}

Proxy模式(代理[延遲]模式)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.