8.設計模式之六:代理模式【結構型模式】

結構型模式描述如何將類或對象按某種佈局組成更大的結構。它分爲類結構型模式和對象結構型模式,前者採用繼承機制來組織接口和類,後者釆用組合或聚合來組合對象。python

因爲組合關係或聚合關係比繼承關係耦合度低,知足「合成複用原則」,因此對象結構型模式比類結構型模式具備更大的靈活性。安全

在有些狀況下,一個客戶不能或者不想直接訪問另外一個對象,這時須要找一箇中介幫忙完成某項任務,這個中介就是代理對象。例如,購買火車票不必定要去火車站買,能夠經過 12306 網站或者去火車票代售點買。服務器

定義與特色

代理模式的定義:因爲某些緣由須要給某對象提供一個代理以控制對該對象的訪問。這時,訪問對象不適合或者不能直接引用目標對象,代理對象做爲訪問對象和目標對象之間的中介。佈局

代理模式的主要優勢有:post

  • 代理模式在客戶端與目標對象之間起到一箇中介做用和保護目標對象的做用;
  • 代理對象能夠擴展目標對象的功能;
  • 代理模式能將客戶端與目標對象分離,在必定程度上下降了系統的耦合度;

其主要缺點是:性能

  • 在客戶端和目標對象之間增長一個代理對象,會形成請求處理速度變慢;
  • 增長了系統的複雜度;

結構與實現

代理模式的結構比較簡單,主要是經過定義一個繼承抽象主題的代理來包含真實主題,從而實現對真實主題的訪問,下面來分析其基本結構和實現方法。網站

代理模式的主要角色以下:spa

  1. 抽象主題(Subject)類:經過接口或抽象類聲明真實主題和代理對象實現的業務方法。
  2. 真實主題(Real Subject)類:實現了抽象主題中的具體業務,是代理對象所表明的真實對象,是最終要引用的對象。
  3. 代理(Proxy)類:提供了與真實主題相同的接口,其內部含有對真實主題的引用,它能夠訪問、控制或擴展真實主題的功能。

 

class Subject(object):
    '''
    抽象主題
    '''
    def request(self):
        pass

class RealSubject(Subject):
    def request(self):
        print("訪問真實主題類")

class Proxy(Subject):
    __real_subject = None
    def request(self):
        if self.__real_subject is None:
            self.__real_subject = RealSubject()
            self.pre_request()
            self.__real_subject.request()
            self.aft_request()


    def pre_request(self):
        print("訪問真實主題以前的預處理。")

    def aft_request(self):
        print("訪問真實主題以後的後續處理。")

if __name__ == '__main__':
    p = Proxy()
    p.request()
訪問真實主題以前的預處理。
訪問真實主題類
訪問真實主題以後的後續處理。

應用實例

【例1】韶關「天街e角」公司是一家婺源特產公司的代理公司,用代理模式實現。設計

分析:本實例中的「婺源特產公司」經營許多婺源特產,它是真實主題,提供了顯示特產的 display() 方法。而韶關「天街e角」公司是婺源特產公司特產的代理,經過調用婺源特產公司的 display() 方法顯示代理產品,固然它能夠增長一些額外的處理,如包裝或加價等。客戶可經過「天街e角」代理公司間接訪問「婺源特產公司」的產品,圖所示是公司的結構圖。代理

class Specially(object):
    def display(self):
        pass

class RealSpecially(Specially):
    def display(self):
        print("「婺源特產公司」經營許多婺源特產")

class SgProxy(Specially):
    __real_specially = None
    def display(self):
        if self.__real_specially is None:
            self.__real_specially = RealSpecially()
            self.pre_opt()
            self.__real_specially.display()
            self.post_opt()

    def pre_opt(self):
        print("代理商打包")

    def post_opt(self):
        print("代理商發貨")

if __name__ == '__main__':
    sp = SgProxy()
    sp.display()
代理商打包
「婺源特產公司」經營許多婺源特產
代理商發貨

應用場景

前面分析了代理模式的結構與特色,如今來分析如下的應用場景。

  • 遠程代理,這種方式一般是爲了隱藏目標對象存在於不一樣地址空間的事實,方便客戶端訪問。例如,用戶申請某些網盤空間時,會在用戶的文件系統中創建一個虛擬的硬盤,用戶訪問虛擬硬盤時實際訪問的是網盤空間。
  • 虛擬代理,這種方式一般用於要建立的目標對象開銷很大時。例如,下載一幅很大的圖像須要很長時間,因某種計算比較複雜而短期沒法完成,這時能夠先用小比例的虛擬代理替換真實的對象,消除用戶對服務器慢的感受。
  • 安全代理,這種方式一般用於控制不一樣種類客戶對真實對象的訪問權限。
  • 智能指引,主要用於調用目標對象時,代理附加一些額外的處理功能。例如,增長計算真實對象的引用次數的功能,這樣當該對象沒有被引用時,就能夠自動釋放它。
  • 延遲加載,指爲了提升系統的性能,延遲對目標的加載。例如,Hibernate 中就存在屬性的延遲加載和關聯表的延時加載。

模式的擴展

在前面介紹的代理模式中,代理類中包含了對真實主題的引用,這種方式存在兩個缺點。

  1. 真實主題與代理主題一一對應,增長真實主題也要增長代理。
  2. 設計代理之前真實主題必須事先存在,不太靈活。採用動態代理模式能夠解決以上問題,如 SpringAOP,其結構圖如圖所示。

相關文章
相關標籤/搜索