C#設計模式之代理模式(三)

Liuwei-Sunny發表於2012-11-27

15.4 遠端代理

      遠端代理(Remote Proxy)是一種常用的代理模式,它使得客戶端程式可以訪問在遠端主機上的物件,遠端主機可能具有更好的計算效能與處理速度,可以快速響應並處理客戶端的請求。遠端代理可以將網路的細節隱藏起來,使得客戶端不必考慮網路的存在。客戶端完全可以認為被代理的遠端業務物件是在本地而不是在遠端,而遠端代理物件承擔了大部分的網路通訊工作,並負責對遠端業務方法的呼叫。

       遠端代理示意圖如圖15-5所示,客戶端物件不能直接訪問遠端主機中的業務物件,只能採取間接訪問的方式。遠端業務物件在本地主機中有一個代理物件,該代理物件負責對遠端業務物件的訪問和網路通訊,它對於客戶端物件而言是透明的。客戶端無須關心實現具體業務的是誰,只需要按照服務介面所定義的方式直接與本地主機中的代理物件互動即可。

15-5 遠端代理示意圖

      在基於.NET平臺的分散式技術,例如DCOM(Distribute Component Object Model,分散式元件物件模型)Web Service中,都應用了遠端代理模式,大家可以查閱相關資料進行擴充套件學習。

 

15.5 虛擬代理

       虛擬代理(Virtual Proxy)也是一種常用的代理模式,對於一些佔用系統資源較多或者載入時間較長的物件,可以給這些物件提供一個虛擬代理。在真實物件建立成功之前虛擬代理扮演真實物件的替身,而當真實物件建立之後,虛擬代理將使用者的請求轉發給真實物件。

       通常,在以下兩種情況下可以考慮使用虛擬代理:

        (1) 由於物件本身的複雜性或者網路等原因導致一個物件需要較長的載入時間,此時可以用一個載入時間相對較短的代理物件來代表真實物件。通常在實現時可以結合多執行緒技術,一個執行緒用於顯示代理物件,其他執行緒用於載入真實物件。這種虛擬代理模式可以應用在程式啟動的時候,由於建立代理物件在時間和處理複雜度上要少於建立真實物件,因此,在程式啟動時,可以用代理物件代替真實物件初始化,大大加速了系統的啟動時間。當需要使用真實物件時,再通過代理物件來引用,而此時真實物件可能已經成功載入完畢,可以縮短使用者的等待時間。

      (2) 當一個物件的載入十分耗費系統資源的時候,也非常適合使用虛擬代理。虛擬代理可以讓那些佔用大量記憶體或處理起來非常複雜的物件推遲到使用它們的時候才建立,而在此之前用一個相對來說佔用資源較少的代理物件來代表真實物件,再通過代理物件來引用真實物件。為了節省記憶體,在第一次引用真實物件時再建立物件,並且該物件可被多次重用,在以後每次訪問時需要檢測所需物件是否已經被建立,因此在訪問該物件時需要進行存在性檢測,這需要消耗一定的系統時間,但是可以節省記憶體空間,這是一種用時間換取空間的做法。

       無論是以上哪種情況,虛擬代理都是用一個“虛假”的代理物件來代表真實物件,通過代理物件來間接引用真實物件,可以在一定程度上提高系統的效能。

 

15.6 緩衝代理

       緩衝代理(Cache Proxy)也是一種較為常用的代理模式,它為某一個操作的結果提供臨時的快取儲存空間,以便在後續使用中能夠共享這些結果,從而可以避免某些方法的重複執行,優化系統效能。

       在微軟示例專案PetShop 4.0的業務邏輯層(Business Logic Layer, BLL)中定義了ProductCategoryItem等類,它們封裝了相關的業務方法,用於呼叫資料訪問層(Data Access Layer, DAL)物件訪問資料庫,以獲取相關資料。為了改進系統效能,PetShop 4.0為這些實現方法增加快取機制,引入一個新的物件去控制原來的BLL業務邏輯物件,這些新的物件對應於代理模式中的代理物件。在引入代理模式後,實現了在快取級別上對業務物件的封裝,增強了對業務物件的控制,如果需要訪問的資料在快取中已經存在,則無須再重複執行獲取資料的方法,直接返回儲存在快取中的資料即可。由於原有業務物件(真實物件)和新增代理物件暴露在外的方法是一致的,因而對於呼叫方即客戶端而言,呼叫代理物件與真實物件並沒有實質的區別。

       這些新引入的代理類包括ProductDataProxyCategoryDataProxyItemDataProxy等。下面以PetShop.BLL.Product業務物件為例進行說明,PetShop 4.0為其建立了代理物件ProductDataProxy,並在ProductDataProxyGetProductsByCategory()方法中呼叫了業務邏輯層Product類的GetProductsByCategory()方法,同時增加了快取機制。如圖15-6所示:

15-6 PetShop4.0快取代理示意圖

       在ProductDataProxy類中存在如下程式碼片段:

public static class ProductDataProxy
{
    private static readonly int productTimeout = int.Parse(ConfigurationManager.AppSettings ["ProductCacheDuration"]);
    private static readonly bool enableCaching = bool.Parse(ConfigurationManager. AppSettings["EnableCaching"]); 

    public static IList GetProductsByCategory(string category)
    {        
        Product product = new Product();

        //如果快取被禁用,則直接通過product物件來獲取資料
         if (!enableCaching)
        {
            return product.GetProductsByCategory(category);
        }

        string key = "product_by_category_" + category;
        //從快取中獲取資料
         IList data = (IList )HttpRuntime.Cache[key];  

        //如果快取中沒有資料則執行如下程式碼
          if (data == null)
        {            
          data = product.GetProductsByCategory(category);            
          //通過工廠建立AggregateCacheDependency物件
            AggregateCacheDependency cd = DependencyFacade.GetProductDependency (); 
          //將資料儲存在快取中,並新增必要的AggregateCacheDependency物件
            HttpRuntime.Cache.Add(key, data, cd, DateTime.Now.AddHours(product Timeout), Cache.NoSlidingExpiration, CacheItemPriority.High, null); 
        }
        return data;
    }
        ……
}

       在上述程式碼中,AggregateCacheDependency是從.NET Framework 2.0開始新增的一個類,它負責監視依賴項物件的集合。當這個集合中的任意一個依賴項物件發生改變時,該依賴項物件對應的快取物件都將被自動移除。在此不對AggregateCacheDependency進行詳細說明,大家可以查閱相關資料進行擴充套件學習。

       與業務邏輯層Product物件的GetProductsByCategory()方法相比,上述程式碼增加了快取機制。當快取內不存在相關資料項時,則直接呼叫業務邏輯層ProductGetProductsByCategory()方法來獲取資料,並將其與對應的AggregateCacheDependency物件一起儲存在快取中。在ProductDataProxy類的每一個業務方法中都例項化了Product類,再呼叫Product類的相應方法,因此ProductDataProxyProduct之間屬於依賴關係,這是標準代理模式的一種變形,可以按照標準代理模式對其進行改進,包括引入高層的抽象介面。

【作者:劉偉(Sunny)  http://blog.csdn.net/lovelion

相關文章