淺談C#中的延遲加載(2)——善用virtual

來源: youguanbumen.net  發布時間: 2011-02-14 23:08  閱讀: 5387 次  推薦: 2   原文鏈接   [收藏]  
摘要:這篇文章介紹一種方法來隱藏這個屬性,同時又可以達到延遲加載的目的,更重要的是這一切都是在之前的基礎上來完成的,不需要改變原來使用到實體類的地方的代碼。

  之前的文章"淺談C#中的延遲加載(1)——善用委托"中介紹了三層結構中在Model層對實體類的屬性實現延遲加載的方法,該方法利用C#中的委托來實現,最后雖然延遲加載的目的得以實現,但是給客戶端(例如UI層)暴露了不必要的屬性(一個委托對象,我使用了泛型的Fun類來實現)。這篇文章介紹一種方法來隱藏這個屬性,同時又可以達到延遲加載的目的,更重要的是這一切都是在之前的基礎上來完成的,不需要改變原來使用到實體類的地方的代碼。

  按照慣例,我們考慮一下想要我們的代碼達到什么效果:首先在Model.Acticle(文章實體類)中的Category屬性和原來一樣,只在需要的時候通過調用委托來獲取文章所屬分類(Model.ArticleCategory類)。同時這個委托是不被客戶端(例如UI層)代碼看到的。。。設計模式中有一句話,大致的意思是通常在兩個事物之間加上一個中間層,可以把事情變得簡單,于是我們這樣考慮,能不能加多一個中間層來實現呢?

  把Category屬性定義為虛擬的(virtual),去掉委托,繼承Model.Acticle類實現一個子類,把委托放到到這個子類里面來,由個子類里面去實現Category屬性的get選擇器,客戶端訪問的是一個用該子類做實例化的Model.Acticle類對象,這樣一來客戶端代碼訪問的依舊是Model.Acticle類,但是看不到用于實現延遲加載的委托卻又能在Category屬性中獲取到需要的數據。呵呵,由于我是寫文章的人,所以覺得這個思路很好理解,但是看文字的您可能感覺有點暈,下面用代碼來說明應該就清楚了。

  首先我們修改Model.Acticle類,給他瘦身,瘦身結果如下:

 
c#代碼
// 文章實體類
  public class Article
 {
 
public int ArticleID { get; set; }
 
public string Title { get; set; }
 
public string Cotnent{ get; set; }
 
public DateTime CreateTime { get; set; }
 
public int CategoryID { get; set; }
 
// 文章所屬分類
  public virtual Model.ArticleCategory Category
 {

get;
}
 }

  對比上一篇文章,可以發現作為延遲加載用的委托不見了,另外就是Category的get選擇器中不再有任何邏輯代碼,并且該屬性被聲明為virtual了。

  下一步我們創建多一層出來。新建一個名為DModel的類庫(注意:該層需要引用Model層,然后被Dal層引用)。接下來在DModel層也創建一個Article類,沒錯!用他來繼承Model.Acticle類。Dmodel.Acticle長成下面這個樣子:

 
c#代碼
 
namespace DModel{
 
// 文章 
public class Article : Model.Article
 {
 
// 所屬分類
 protected Model.ArticleCategory _category;
 
public override Model.ArticleCategory Category
 {
 
get
 {
if (_category == null)
{

if (CategoryLazyLoader != null)
{
 _category
= CategoryLazyLoader(CategoryID);
 }

else
 {
_category
= null;
 }
 }
 
return _category;
 }
 }
 
// 文章分類延時加載器(委托)
 public Func<int, Model.ArticleCategory> CategoryLazyLoader { get; set; } }}

  是的,看到了么,委托跑這兒來了,并且他實現了Model.Acticle的Category屬性的get選擇器,里面的邏輯是不是也很熟悉呢。

  接著還有一個地方要做點小修改,就是Dal層中獲取一個文章實體類的方法,也就是前一篇文章中寫到的public Model.Article GetArticleById(int articleId)方法了,修改后如下:

 
c#代碼
 
// 根據文章ID獲取文章實體類對象public Model.Article GetArticleById(int articleId){
 
// 從數據庫中取出數據,得到一個DateRow或者DateRader之類的東東然后初始化一個文章實體類對象
 DModel.Article article = ... // ...是代碼 - -!
 
// 創建文章分類數據訪問對象
 Dal.ArticleCategory articleCategory = new Dal.ArticleCategory();
 
// 指定延時加載委托
 article.CategoryLazyLoader = articleCategory.GetArticleCategoryById;
 
// 返回文章對象
 return article;}

  請注意上面代碼中這一句,DModel.Article article = ... // ...是代碼 - -!,我們得到一個DModel.Article對象,最后以Model.Article的形式返回(C#中的裝箱,是吧~)。再次告訴你的同事吧,你不用去管那個委托了,因為你現在拿到的Mode.Article對象中看不到那玩意,反正對你也沒用。果然,看不見了,延遲加載的目的也達到鳥! 總結一下,本文講的比前一篇文章講的東西還少,主要記住三點: 1、把Category屬性聲明為虛擬的; 2、把Category原來的邏輯代碼推遲到子類里面實現; 3、用子類(DModel.Acticle)實例話父類(Model.Acticle)。

  好了,用這個方法把項目里面類似Category這樣的實體類屬性修改為virtial吧,創建子類去重寫它實現延遲加載,子類只有Dal層知道它的存在,Bll層和UI層對此一無所知,他們還是和原來一樣用著,啥都不用修改,但是代碼的效率明顯有了提高,現在屬性沒有被使用就不會讀取數據庫了,數據庫的壓力也減少了^_^!!!

  這一切看起來似乎沒問題,直到一個BUG被發現......在一個實體類中,有一個屬性,按照之前的邏輯是我們給它賦值的時候,會對其他屬性做相應的修改,現在給重寫掉了,之前的邏輯,沒拉.(待續)

2
0
 
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()