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所示:
圖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類型對象。