代码改变世界

PetShop之ASP.NET缓存--three

2007-04-27 10:07  DQ  阅读(261)  评论(0)    收藏  举报
以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业务对象建立的代理对象则被“投闲散置”,仅仅作为一种设计方法的展示而 “幸存”与整个系统的源代码中。