Proxy 模式


您打算開發一個文書編輯器,文件中可以有圖片,如果您在載入文件時連同圖片一同載入:
class Document {
    private Image image;
    ...
    Document() {
        image = new Image("doc://images/xxx.jpg");
    }

    void scroll() {
        ...
        image.draw();
        ...
    }
}

若文件中有很多圖片,則開啟文件的速度可能非常慢,但實際上,圖片可能在文件的中間,開啟文件後顯示第一頁時,圖片並不用繪製出來,在一開始載入所有的圖 片實非必要,若可以的話,在要顯示時再載入該圖片,將可以加快開啟文件的速度。

您可以改寫為這種方式:
interface Graphics {
    void draw();
}

class Image implements Graphics {
    ...   
    public void draw() {
        ...
    }
}

class ImageProxy implements Graphicss {
    private Graphics image;
    private String filename;
    ImageProxy(String 
filename) {
        this.
filenamefilename;
    }
    public void draw() {
        if(image == null) {
            image = new Image(filename);
        }
        image.draw();
    }
}


class Document {

    private Graphics image;
    Document() {
        image = new ImageProxy("doc://images/xxx.jpg");
    }

    void scroll() {
        ...
        image.draw();
        ...
    }
}

文件載入並建立Document時,建立的是ImageProxy實例,在真正需要繪製圖片時,才會真正建立Image實例並進行繪製動作,使用這種方 式,即使文件中圖片很多,也不至於拖累開啟文件的速度。

以UML圖來表示這個例子:


以Python來示意一下實現:
class Image:
    ...
    def draw(self):
        ...

class ImageProxy:
    def __init__(self, filename):
        self.image = None
        self.filename = filename
    def draw(self):
        if not self.image:
            self.image = Image(filename)
        self.image.draw()

class Document:
    def __init__(self):
        self.image = ImageProxy("doc://images/xxx.jpg")
    def scroll(self):
        ...
        self.image.draw()
        ...

這是Proxy模式的一個實例,您為其它的物件提供一種代理,以控制對這個物件的訪問,根據您的目的不同,您的代理物件將負有不同的責任,因而產生多種不 同的代理情況。


在調用RealSubject的request()之前,Proxy物件也許會有一些預先處理的操作,就假設我們組織為preOperation()與 postOperation()好了,當客戶對Proxy發出request()請求後,一個可能的時序圖如下所示:
Proxy


您的preOperation()與postOperation()正決定了Proxy模式使用於何種情況,例如可能是在某個方法呼叫前後作日誌的動作, 或甚至作為攔截器,以條件決定是否呼叫真正的物件等。