亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

PetShop

系統 1918 0

PetShop作為一個B2C的寵物網上商店,需要充分考慮訪客的用戶體驗,如果因為數據量大而導致Web服務器的響應不及時,頁面和查詢數據遲遲得不到結果,會因此而破壞客戶訪問網站的心情,在耗盡耐心的等待后,可能會失去這一部分客戶。無疑,這是非常糟糕的結果。因而在對其進行體系架構設計時,整個系統的性能就顯得殊為重要。然而,我們不能因噎廢食,因為專注于性能而忽略數據的正確性。在PetShop 3.0版本以及之前的版本,因為ASP.NET緩存的局限性,這一問題并沒有得到很好的解決。PetShop 4.0則引入了SqlCacheDependency特性,使得系統對緩存的處理較之以前大為改觀。

4.3.1 CacheDependency接口

PetShop 4.0引入了SqlCacheDependency特性,對Category、Product和Item數據表對應的緩存實施了SQL Cache Invalidation技術。當對應的數據表數據發生更改后,該技術能夠將相關項從緩存中移除。實現這一技術的核心是 SqlCacheDependency類,它繼承了CacheDependency類。然而為了保證整個架構的可擴展性,我們也允許設計者建立自定義的 CacheDependency類,用以擴展緩存依賴。這就有必要為CacheDependency建立抽象接口,并在web.config文件中進行配置。

在PetShop 4.0的命名空間PetShop.ICacheDependency中,定義了名為IPetShopCacheDependency接口,它僅包含了一個接口方法:
public interface IPetShopCacheDependency
{
AggregateCacheDependency GetDependency();
}

AggregateCacheDependency是.Net Framework 2.0新增的一個類,它負責監視依賴項對象的集合。當這個集合中的任意一個依賴項對象發生改變時,該依賴項對象對應的緩存對象都將被自動移除。
AggregateCacheDependency 類起到了組合CacheDependency對象的作用,它可以將多個CacheDependency對象甚至于不同類型的 CacheDependency對象與緩存項建立關聯。由于PetShop需要為Category、Product和Item數據表建立依賴項,因而 IPetShopCacheDependency的接口方法GetDependency()其目的就是返回建立了這些依賴項的 AggregateCacheDependency對象。

4.3.2 CacheDependency實現

CacheDependency的實現正是為Category、Product和Item數據表建立了對應的SqlCacheDependency類型的依賴項,如代碼所示:
public abstract class TableDependency : IPetShopCacheDependency
{
// This is the separator that's used in web.config
protected char[] configurationSeparator = new char[] { ',' };

protected AggregateCacheDependency dependency = new AggregateCacheDependency();
protected TableDependency(string configKey)
{
string dbName = ConfigurationManager.AppSettings["CacheDatabaseName"];
string tableConfig = ConfigurationManager.AppSettings[configKey];
string[] tables = tableConfig.Split(configurationSeparator);

foreach (string tableName in tables)
dependency.Add(new SqlCacheDependency(dbName, tableName));
}
public AggregateCacheDependency GetDependency()
{
return dependency;
}
}

需要建立依賴項的數據庫與數據表都配置在web.config文件中,其設置如下:
<add key="CacheDatabaseName" value="MSPetShop4"/>
<add key="CategoryTableDependency" value="Category"/>
<add key="ProductTableDependency" value="Product,Category"/>
<add key="ItemTableDependency" value="Product,Category,Item"/>

根據各個數據表間的依賴關系,因而不同的數據表需要建立的依賴項也是不相同的,從配置文件中的value值可以看出。然而不管建立依賴項的多寡,其創建的行為邏輯都是相似的,因而在設計時,抽象了一個共同的類TableDependency,并通過建立帶參數的構造函數,完成對依賴項的建立。由于接口方法 GetDependency()的實現中,返回的對象dependency是在受保護的構造函數創建的,因此這里的實現方式也可以看作是Template Method模式的靈活運用。例如TableDependency的子類Product,就是利用父類的構造函數建立了Product、Category 數據表的SqlCacheDependency依賴:
public class Product : TableDependency
{
public Product() : base("ProductTableDependency") { }
}

如果需要自定義CacheDependency,那么創建依賴項的方式又有不同。然而不管是創建SqlCacheDependency對象,還是自定義的 CacheDependency對象,都是將這些依賴項添加到AggregateCacheDependency類中,因而我們也可以為自定義 CacheDependency建立專門的類,只要實現IPetShopCacheDependency接口即可。

4.3.3 CacheDependency工廠

繼承了抽象類TableDependency的Product、Category和Item類均需要在調用時創建各自的對象。由于它們的父類 TableDependency實現了接口IPetShopCacheDependency,因而它們也間接實現了 IPetShopCacheDependency接口,這為實現工廠模式提供了前提。

在PetShop 4.0中,依然利用了配置文件和反射技術來實現工廠模式。命名空間PetShop.CacheDependencyFactory中,類DependencyAccess即為創建IPetShopCacheDependency對象的工廠類:
public static class DependencyAccess
{
public static IPetShopCacheDependency CreateCategoryDependency()
{
return LoadInstance("Category");
}
public static IPetShopCacheDependency CreateProductDependency()
{
return LoadInstance("Product");
}
public static IPetShopCacheDependency CreateItemDependency()
{
return LoadInstance("Item");
}
private static IPetShopCacheDependency LoadInstance(string className)
{
string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
string fullyQualifiedClass = path + "." + className;
return (IPetShopCacheDependency)Assembly.Load(path).CreateInstance(fullyQualifiedClass);
}
}
整個工廠模式的實現如圖4-3所示:

C:\Documents and Settings\zhangl\桌面\20061102063110194.gif PetShop
圖4-3 CacheDependency工廠

雖然DependencyAccess類創建了實現了IPetShopCacheDependency接口的類Category、Product、 Item,然而我們之所以引入IPetShopCacheDependency接口,其目的就在于獲得創建了依賴項的 AggregateCacheDependency類型的對象。我們可以調用對象的接口方法GetDependency(),如下所示:
AggregateCacheDependency dependency = DependencyAccess.CreateCategoryDependency().GetDependency();

為了方便調用者,似乎我們可以對DependencyAccess類進行改進,將原有的CreateCategoryDependency()方法,修改為創建AggregateCacheDependency類型對象的方法。

然而這樣的做法擾亂了作為工廠類的DependencyAccess的本身職責,且創建IPetShopCacheDependency接口對象的行為仍然有可能被調用者調用,所以保留原有的DependencyAccess類仍然是有必要的。

在PetShop 4.0的設計中,是通過引入Facade模式以方便調用者更加簡單地獲得AggregateCacheDependency類型對象。

4.3.4 引入Facade模式

利用Facade模式可以將一些復雜的邏輯進行包裝,以方便調用者對這些復雜邏輯的調用。就好像提供一個統一的門面一般,將內部的子系統封裝起來,統一為一個高層次的接口。一個典型的Facade模式示意圖如下所示:

PetShop
圖4-4 Facade模式

Facade 模式的目的并非要引入一個新的功能,而是在現有功能的基礎上提供一個更高層次的抽象,使得調用者可以直接調用,而不用關心內部的實現方式。以 CacheDependency工廠為例,我們需要為調用者提供獲得AggregateCacheDependency對象的簡便方法,因而創建了 DependencyFacade類:
public static class DependencyFacade
{
private static readonly string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
public static AggregateCacheDependency GetCategoryDependency()
{
if (!string.IsNullOrEmpty(path))
return DependencyAccess.CreateCategoryDependency().GetDependency();
else
return null;
}
public static AggregateCacheDependency GetProductDependency()
{
if (!string.IsNullOrEmpty(path))
return DependencyAccess.CreateProductDependency().GetDependency();
else
return null;
}
public static AggregateCacheDependency GetItemDependency()
{
if (!string.IsNullOrEmpty(path))
return DependencyAccess.CreateItemDependency().GetDependency();
else
return null;
}
}

DependencyFacade類封裝了獲取AggregateCacheDependency類型對象的邏輯,如此一來,調用者可以調用相關方法獲得創建相關依賴項的AggregateCacheDependency類型對象:
AggregateCacheDependency dependency = DependencyFacade.GetCategoryDependency();

比起直接調用DependencyAccess類的GetDependency()方法而言,除了方法更簡單之外,同時它還對CacheDependencyAssembly配置節進行了判斷,如果其值為空,則返回null對象。

在PetShop.Web的App_Code文件夾下,靜態類WebUtility的GetCategoryName()和GetProductName()方法調用了DependencyFacade類。例如GetCategoryName()方法:
public static string GetCategoryName(string categoryId)
{
Category category = new Category();
if (!enableCaching)
return category.GetCategory(categoryId).Name;

string cacheKey = string.Format(CATEGORY_NAME_KEY, categoryId);

// 檢查緩存中是否存在該數據項;
string data = (string)HttpRuntime.Cache[cacheKey];
if (data == null)
{
// 通過web.config的配置獲取duration值;
int cacheDuration = int.Parse(ConfigurationManager.AppSettings["CategoryCacheDuration"]);
// 如果緩存中不存在該數據項,則通過業務邏輯層訪問數據庫獲取;
data = category.GetCategory(categoryId).Name;
// 通過Facade類創建AggregateCacheDependency對象;
AggregateCacheDependency cd = DependencyFacade.GetCategoryDependency();
// 將數據項以及AggregateCacheDependency 對象存儲到緩存中;
HttpRuntime.Cache.Add(cacheKey, data, cd, DateTime.Now.AddHours(cacheDuration), Cache.NoSlidingExpiration, CacheItemPriority.High, null);
}
return data;
}

GetCategoryName ()方法首先會檢查緩存中是否已經存在CategoryName數據項,如果已經存在,就通過緩存直接獲取數據;否則將通過業務邏輯層調用數據訪問層訪問數據庫獲得CategoryName,在獲得了CategoryName后,會將新獲取的數據連同DependencyFacade類創建的 AggregateCacheDependency對象添加到緩存中。

WebUtility靜態類被表示層的許多頁面所調用,例如Product頁面:
public partial class Products : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Page.Title = WebUtility.GetCategoryName(Request.QueryString["categoryId"]);
}
}

顯示頁面title的邏輯是放在Page_Load事件方法中,因而每次打開該頁面都要執行獲取CategoryName的方法。如果沒有采用緩存機制,當Category數據較多時,頁面的顯示就會非常緩慢。

4.3.5 引入Proxy模式

業務邏輯層BLL中與Product、Category、Item有關的業務方法,其實現邏輯是調用數據訪問層(DAL)對象訪問數據庫,以獲取相關數據。為了改善系統性能,我們就需要為這些實現方法增加緩存機制的邏輯。當我們操作增加了緩存機制的業務對象時,對于調用者而言,應與BLL業務對象的調用保持一致。也即是說,我們需要引入一個新的對象去控制原來的BLL業務對象,這個新的對象就是Proxy模式中的代理對象。

以PetShop.BLL.Product業務對象為例,PetShop為其建立了代理對象ProductDataProxy,并在GetProductByCategory()等方法中,引入了緩存機制,例如:
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();

if (!enableCaching)
return product.GetProductsByCategory(category);

string key = "product_by_category_" + category;
IList data = (IList )HttpRuntime.Cache[key];

// Check if the data exists in the data cache
if (data == null)
{
data = product.GetProductsByCategory(category);

// Create a AggregateCacheDependency object from the factory
AggregateCacheDependency cd = DependencyFacade.GetProductDependency();

// Store the output in the data cache, and Add the necessary AggregateCacheDependency object
HttpRuntime.Cache.Add(key, data, cd, DateTime.Now.AddHours(productTimeout), Cache.NoSlidingExpiration, CacheItemPriority.High, null);
}
return data;
}
}

與業務邏輯層Product對象的GetProductsByCategory()方法相比,增加了緩存機制。當緩存內不存在相關數據項時,則直接調用業務邏輯層Product的GetProductsByCategory()方法來獲取數據,并將其與對應的 AggregateCacheDependency對象一起存儲在緩存中。

引入Proxy模式,實現了在緩存級別上對業務對象的封裝,增強了對業務對象的控制。由于暴露在對象外的方法是一致的,因而對于調用方而言,調用代理對象與真實對象并沒有實質的區別。

從職責分離與分層設計的角度分析,我更希望這些Proxy對象是被定義在業務邏輯層中,而不像在PetShop的設計那樣,被劃分到表示層UI中。此外,如果需要考慮程序的可擴展性與可替換性,我們還可以為真實對象與代理對象建立統一的接口或抽象類。然而,單以PetShop的表示層調用來看,采用靜態類與靜態方法的方式,或許更為合理。我們需要謹記,“過度設計”是軟件設計的警戒線。

如果需要對UI層采用緩存機制,將應用程序數據存放到緩存中,就可以調用這些代理對象。以ProductsControl用戶控件為例,調用方式如下:
productsList.DataSource = ProductDataProxy.GetProductsByCategory(categoryKey);

productsList對象屬于自定義的CustomList類型,這是一個派生自System.Web.UI.WebControls.DataList控件的類,它的DataSource屬性可以接受IList集合對象。
不過在PetShop 4.0的設計中,對于類似于ProductsControl類型的控件而言,采用的緩存機制是頁輸出緩存。我們可以從ProductsControl.ascx頁面的Source代碼中發現端倪:
<%@ OutputCache Duration="100000" VaryByParam="page;categoryId" %>

與ASP.NET 1.x的頁輸出緩存不同的是,在ASP.NET 2.0中,為ASP.NET用戶控件新引入了CachePolicy屬性,該屬性的類型為ControlCachePolicy類,它以編程方式實現了對 ASP.NET用戶控件的輸出緩存設置。我們可以通過設置ControlCachePolicy類的Dependency屬性,來設置與該用戶控件相關的依賴項,例如在ProductsControl用戶控件中,進行如下的設置:
protected void Page_Load(object sender, EventArgs e)
{
this.CachePolicy.Dependency = DependencyFacade.GetProductDependency();
}

采用頁輸出緩存,并且利用ControlCachePolicy設置輸出緩存,能夠將業務數據與整個頁面放入到緩存中。這種方式比起應用程序緩存而言,在性能上有很大的提高。同時,它又通過引入的SqlCacheDependency特性有效地避免了“數據過期”的缺點,因而在PetShop 4.0中被廣泛采用。相反,之前為Product、Category、Item業務對象建立的代理對象則被“投閑散置”,僅僅作為一種設計方法的展示而 “幸存”與整個系統的源代碼中。

<img onload="if(this.width>515)this.width=515" src="file:///C:/DOCUME%7E1/zhangl/LOCALS%7E1/Temp/moz-screenshot.jpg" alt="">PetShop作為一個B2C的寵物網上商店,需要充分考慮訪客的用戶體驗,如果因為數據量大而導致Web服務器的響應不及時,頁面和查詢數據遲遲得不到結果,會因此而破壞客戶訪問網站的心情,在耗盡耐心的等待后,可能會失去這一部分客戶。無疑,這是非常糟糕的結果。因而在對其進行體系架構設計時,整個系統的性能就顯得殊為重要。然而,我們不能因噎廢食,因為專注于性能而忽略數據的正確性。在PetShop 3.0版本以及之前的版本,因為ASP.NET緩存的局限性,這一問題并沒有得到很好的解決。PetShop 4.0則引入了SqlCacheDependency特性,使得系統對緩存的處理較之以前大為改觀。

4.3.1 CacheDependency接口

PetShop 4.0引入了SqlCacheDependency特性,對Category、Product和Item數據表對應的緩存實施了SQL Cache Invalidation技術。當對應的數據表數據發生更改后,該技術能夠將相關項從緩存中移除。實現這一技術的核心是 SqlCacheDependency類,它繼承了CacheDependency類。然而為了保證整個架構的可擴展性,我們也允許設計者建立自定義的 CacheDependency類,用以擴展緩存依賴。這就有必要為CacheDependency建立抽象接口,并在web.config文件中進行配置。

在PetShop 4.0的命名空間PetShop.ICacheDependency中,定義了名為IPetShopCacheDependency接口,它僅包含了一個接口方法:
public interface IPetShopCacheDependency
{
AggregateCacheDependency GetDependency();
}

AggregateCacheDependency是.Net Framework 2.0新增的一個類,它負責監視依賴項對象的集合。當這個集合中的任意一個依賴項對象發生改變時,該依賴項對象對應的緩存對象都將被自動移除。
AggregateCacheDependency 類起到了組合CacheDependency對象的作用,它可以將多個CacheDependency對象甚至于不同類型的 CacheDependency對象與緩存項建立關聯。由于PetShop需要為Category、Product和Item數據表建立依賴項,因而 IPetShopCacheDependency的接口方法GetDependency()其目的就是返回建立了這些依賴項的 AggregateCacheDependency對象。

4.3.2 CacheDependency實現

CacheDependency的實現正是為Category、Product和Item數據表建立了對應的SqlCacheDependency類型的依賴項,如代碼所示:
public abstract class TableDependency : IPetShopCacheDependency
{
// This is the separator that's used in web.config
protected char[] configurationSeparator = new char[] { ',' };

protected AggregateCacheDependency dependency = new AggregateCacheDependency();
protected TableDependency(string configKey)
{
string dbName = ConfigurationManager.AppSettings["CacheDatabaseName"];
string tableConfig = ConfigurationManager.AppSettings[configKey];
string[] tables = tableConfig.Split(configurationSeparator);

foreach (string tableName in tables)
dependency.Add(new SqlCacheDependency(dbName, tableName));
}
public AggregateCacheDependency GetDependency()
{
return dependency;
}
}

需要建立依賴項的數據庫與數據表都配置在web.config文件中,其設置如下:





根據各個數據表間的依賴關系,因而不同的數據表需要建立的依賴項也是不相同的,從配置文件中的value值可以看出。然而不管建立依賴項的多寡,其創建的行為邏輯都是相似的,因而在設計時,抽象了一個共同的類TableDependency,并通過建立帶參數的構造函數,完成對依賴項的建立。由于接口方法 GetDependency()的實現中,返回的對象dependency是在受保護的構造函數創建的,因此這里的實現方式也可以看作是Template Method模式的靈活運用。例如TableDependency的子類Product,就是利用父類的構造函數建立了Product、Category 數據表的SqlCacheDependency依賴:
public class Product : TableDependency
{
public Product() : base("ProductTableDependency") { }
}

如果需要自定義CacheDependency,那么創建依賴項的方式又有不同。然而不管是創建SqlCacheDependency對象,還是自定義的 CacheDependency對象,都是將這些依賴項添加到AggregateCacheDependency類中,因而我們也可以為自定義 CacheDependency建立專門的類,只要實現IPetShopCacheDependency接口即可。

4.3.3 CacheDependency工廠

繼承了抽象類TableDependency的Product、Category和Item類均需要在調用時創建各自的對象。由于它們的父類 TableDependency實現了接口IPetShopCacheDependency,因而它們也間接實現了 IPetShopCacheDependency接口,這為實現工廠模式提供了前提。

在PetShop 4.0中,依然利用了配置文件和反射技術來實現工廠模式。命名空間PetShop.CacheDependencyFactory中,類DependencyAccess即為創建IPetShopCacheDependency對象的工廠類:
public static class DependencyAccess
{
public static IPetShopCacheDependency CreateCategoryDependency()
{
return LoadInstance("Category");
}
public static IPetShopCacheDependency CreateProductDependency()
{
return LoadInstance("Product");
}
public static IPetShopCacheDependency CreateItemDependency()
{
return LoadInstance("Item");
}
private static IPetShopCacheDependency LoadInstance(string className)
{
string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
string fullyQualifiedClass = path + "." + className;
return (IPetShopCacheDependency)Assembly.Load(path).CreateInstance(fullyQualifiedClass);
}
}
整個工廠模式的實現如圖4-3所示:

C:\Documents and Settings\zhangl\桌面\20061102063110194.gif
圖4-3 CacheDependency工廠

雖然DependencyAccess類創建了實現了IPetShopCacheDependency接口的類Category、Product、 Item,然而我們之所以引入IPetShopCacheDependency接口,其目的就在于獲得創建了依賴項的 AggregateCacheDependency類型的對象。我們可以調用對象的接口方法GetDependency(),如下所示:
AggregateCacheDependency dependency = DependencyAccess.CreateCategoryDependency().GetDependency();

為了方便調用者,似乎我們可以對DependencyAccess類進行改進,將原有的CreateCategoryDependency()方法,修改為創建AggregateCacheDependency類型對象的方法。

然而這樣的做法擾亂了作為工廠類的DependencyAccess的本身職責,且創建IPetShopCacheDependency接口對象的行為仍然有可能被調用者調用,所以保留原有的DependencyAccess類仍然是有必要的。

在PetShop 4.0的設計中,是通過引入Facade模式以方便調用者更加簡單地獲得AggregateCacheDependency類型對象。

4.3.4 引入Facade模式

利用Facade模式可以將一些復雜的邏輯進行包裝,以方便調用者對這些復雜邏輯的調用。就好像提供一個統一的門面一般,將內部的子系統封裝起來,統一為一個高層次的接口。一個典型的Facade模式示意圖如下所示:


圖4-4 Facade模式

Facade 模式的目的并非要引入一個新的功能,而是在現有功能的基礎上提供一個更高層次的抽象,使得調用者可以直接調用,而不用關心內部的實現方式。以 CacheDependency工廠為例,我們需要為調用者提供獲得AggregateCacheDependency對象的簡便方法,因而創建了 DependencyFacade類:
public static class DependencyFacade
{
private static readonly string path = ConfigurationManager.AppSettings["CacheDependencyAssembly"];
public static AggregateCacheDependency GetCategoryDependency()
{
if (!string.IsNullOrEmpty(path))
return DependencyAccess.CreateCategoryDependency().GetDependency();
else
return null;
}
public static AggregateCacheDependency GetProductDependency()
{
if (!string.IsNullOrEmpty(path))
return DependencyAccess.CreateProductDependency().GetDependency();
else
return null;
}
public static AggregateCacheDependency GetItemDependency()
{
if (!string.IsNullOrEmpty(path))
return DependencyAccess.CreateItemDependency().GetDependency();
else
return null;
}
}

DependencyFacade類封裝了獲取AggregateCacheDependency類型對象的邏輯,如此一來,調用者可以調用相關方法獲得創建相關依賴項的AggregateCacheDependency類型對象:
AggregateCacheDependency dependency = DependencyFacade.GetCategoryDependency();

比起直接調用DependencyAccess類的GetDependency()方法而言,除了方法更簡單之外,同時它還對CacheDependencyAssembly配置節進行了判斷,如果其值為空,則返回null對象。

在PetShop.Web的App_Code文件夾下,靜態類WebUtility的GetCategoryName()和GetProductName()方法調用了DependencyFacade類。例如GetCategoryName()方法:
public static string GetCategoryName(string categoryId)
{
Category category = new Category();
if (!enableCaching)
return category.GetCategory(categoryId).Name;

string cacheKey = string.Format(CATEGORY_NAME_KEY, categoryId);

// 檢查緩存中是否存在該數據項;
string data = (string)HttpRuntime.Cache[cacheKey];
if (data == null)
{
// 通過web.config的配置獲取duration值;
int cacheDuration = int.Parse(ConfigurationManager.AppSettings["CategoryCacheDuration"]);
// 如果緩存中不存在該數據項,則通過業務邏輯層訪問數據庫獲取;
data = category.GetCategory(categoryId).Name;
// 通過Facade類創建AggregateCacheDependency對象;
AggregateCacheDependency cd = DependencyFacade.GetCategoryDependency();
// 將數據項以及AggregateCacheDependency 對象存儲到緩存中;
HttpRuntime.Cache.Add(cacheKey, data, cd, DateTime.Now.AddHours(cacheDuration), Cache.NoSlidingExpiration, CacheItemPriority.High, null);
}
return data;
}

GetCategoryName ()方法首先會檢查緩存中是否已經存在CategoryName數據項,如果已經存在,就通過緩存直接獲取數據;否則將通過業務邏輯層調用數據訪問層訪問數據庫獲得CategoryName,在獲得了CategoryName后,會將新獲取的數據連同DependencyFacade類創建的 AggregateCacheDependency對象添加到緩存中。

WebUtility靜態類被表示層的許多頁面所調用,例如Product頁面:
public partial class Products : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Page.Title = WebUtility.GetCategoryName(Request.QueryString["categoryId"]);
}
}

顯示頁面title的邏輯是放在Page_Load事件方法中,因而每次打開該頁面都要執行獲取CategoryName的方法。如果沒有采用緩存機制,當Category數據較多時,頁面的顯示就會非常緩慢。

4.3.5 引入Proxy模式

業務邏輯層BLL中與Product、Category、Item有關的業務方法,其實現邏輯是調用數據訪問層(DAL)對象訪問數據庫,以獲取相關數據。為了改善系統性能,我們就需要為這些實現方法增加緩存機制的邏輯。當我們操作增加了緩存機制的業務對象時,對于調用者而言,應與BLL業務對象的調用保持一致。也即是說,我們需要引入一個新的對象去控制原來的BLL業務對象,這個新的對象就是Proxy模式中的代理對象。

以PetShop.BLL.Product業務對象為例,PetShop為其建立了代理對象ProductDataProxy,并在GetProductByCategory()等方法中,引入了緩存機制,例如:
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();

if (!enableCaching)
return product.GetProductsByCategory(category);

string key = "product_by_category_" + category;
IList data = (IList )HttpRuntime.Cache[key];

// Check if the data exists in the data cache
if (data == null)
{
data = product.GetProductsByCategory(category);

// Create a AggregateCacheDependency object from the factory
AggregateCacheDependency cd = DependencyFacade.GetProductDependency();

// Store the output in the data cache, and Add the necessary AggregateCacheDependency object
HttpRuntime.Cache.Add(key, data, cd, DateTime.Now.AddHours(productTimeout), Cache.NoSlidingExpiration, CacheItemPriority.High, null);
}
return data;
}
}

與業務邏輯層Product對象的GetProductsByCategory()方法相比,增加了緩存機制。當緩存內不存在相關數據項時,則直接調用業務邏輯層Product的GetProductsByCategory()方法來獲取數據,并將其與對應的 AggregateCacheDependency對象一起存儲在緩存中。

引入Proxy模式,實現了在緩存級別上對業務對象的封裝,增強了對業務對象的控制。由于暴露在對象外的方法是一致的,因而對于調用方而言,調用代理對象與真實對象并沒有實質的區別。

從職責分離與分層設計的角度分析,我更希望這些Proxy對象是被定義在業務邏輯層中,而不像在PetShop的設計那樣,被劃分到表示層UI中。此外,如果需要考慮程序的可擴展性與可替換性,我們還可以為真實對象與代理對象建立統一的接口或抽象類。然而,單以PetShop的表示層調用來看,采用靜態類與靜態方法的方式,或許更為合理。我們需要謹記,“過度設計”是軟件設計的警戒線。

如果需要對UI層采用緩存機制,將應用程序數據存放到緩存中,就可以調用這些代理對象。以ProductsControl用戶控件為例,調用方式如下:
productsList.DataSource = ProductDataProxy.GetProductsByCategory(categoryKey);

productsList對象屬于自定義的CustomList類型,這是一個派生自System.Web.UI.WebControls.DataList控件的類,它的DataSource屬性可以接受IList集合對象。
不過在PetShop 4.0的設計中,對于類似于ProductsControl類型的控件而言,采用的緩存機制是頁輸出緩存。我們可以從ProductsControl.ascx頁面的Source代碼中發現端倪:
&lt;%@ OutputCache Duration="100000" VaryByParam="page;categoryId" %&gt;

與ASP.NET 1.x的頁輸出緩存不同的是,在ASP.NET 2.0中,為ASP.NET用戶控件新引入了CachePolicy屬性,該屬性的類型為ControlCachePolicy類,它以編程方式實現了對 ASP.NET用戶控件的輸出緩存設置。我們可以通過設置ControlCachePolicy類的Dependency屬性,來設置與該用戶控件相關的依賴項,例如在ProductsControl用戶控件中,進行如下的設置:
protected void Page_Load(object sender, EventArgs e)
{
this.CachePolicy.Dependency = DependencyFacade.GetProductDependency();
}

采用頁輸出緩存,并且利用ControlCachePolicy設置輸出緩存,能夠將業務數據與整個頁面放入到緩存中。這種方式比起應用程序緩存而言,在性能上有很大的提高。同時,它又通過引入的SqlCacheDependency特性有效地避免了“數據過期”的缺點,因而在PetShop 4.0中被廣泛采用。相反,之前為Product、Category、Item業務對象建立的代理對象則被“投閑散置”,僅僅作為一種設計方法的展示而 “幸存”與整個系統的源代碼中。

PetShop


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。。?/p>

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲一区二区三区精品国产 | 欧美精品日韩一区二区三区 | 四虎国产永久免费久久 | 最近手机中文字幕1页 | 啊用力嗯快国产在线观看 | 奇米影视盒7777 | 国产欧美二区三区 | 欧美影院一区 | 色猫咪av在线网址 | 伊人五月天综合 | 色一情 | 黑人和黑人激情一级毛片 | 老子理论不卡影院6080 | 久热中文字幕在线观看 | 日本波多野结衣字幕久久 | a色视频| 久热爱免费精品视频在线播放 | 国内精品久久久久鸭 | 国产a区 | 久久精品国产麻豆不卡 | 欧洲a视频 | 久久综合视频网 | 欧美性色欧美a在线观看 | 久草香蕉视频在线观看 | 欧美大片在线观看成人 | 久久综合九色综合97欧美 | 亚洲六月丁香婷婷综合 | 九九热在线视频观看这里只有精品 | 国产高清亚洲 | 波多野结衣久久精品 | 日本精品久久久中文字幕 | 成人美女网 | 国产高清免费 | 免费一级特黄视频 | 手机看片日韩高清国产欧美 | 国产高清精品一级毛片 | 四虎永久在线精品2022 | 国产天天射 | 欧洲一级| 在线亚洲国产精品区 | 欧美狠狠入鲁的视频极速 |