<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      趣味編程:C#中Specification模式的實現(參考答案 - 上)

      2009-09-28 10:34  Jeffrey Zhao  閱讀(13670)  評論(12)    收藏  舉報

      Specification模式的作用是構建可以自由組裝的業務邏輯元素。不過就上篇文章的示例來看,“標準”的Specification模式的實現還是比較麻煩的,簡單的功能也需要較復雜的代碼。不過,既然說是“標準”的方式,自然就是指可以在任意面向對象語言中使用的實現方式,不過我們使用的是C#,在實際開發過程中,我們可以利用C#如今的強大特性來實現出更容易使用,更輕量級的Specification模式。

      當然,有利也有弊,在使用“標準”還是“輕量級”的問題上,還要根據你的需求來進行選擇。

      Specification模式的關鍵在于,Specification類有一個IsSatisifiedBy函數,用于校驗某個對象是否滿足該Specification所表示的條件。多個Specification對象可以組裝起來,并生成新Specification對象,這便可以形成高度可定制的業務邏輯。從中可以看出,一個Specification對象的關鍵,其實就是一個IsSatisifiedBy方法的邏輯。每種對象,一段邏輯。每個對象的唯一關鍵,也就是這么一段邏輯。因此,我們完全可以構造這么一個“通用”的類型,允許外界將這段邏輯通過構造函數“注入”到Specification對象中:

      public class Specification<T> : ISpecification<T>
      {
          private Func<T, bool> m_isSatisfiedBy;
      
          public Specification(Func<T, bool> isSatisfiedBy)
          {
              this.m_isSatisfiedBy = isSatisfiedBy;
          }
      
          public bool IsSatisfiedBy(T candidate)
          {
              return this.m_isSatisfiedBy(candidate);
          }
      }

      嗯嗯,這也是一種依賴注入。在普通的面向對象語言中,承載一段邏輯的最小單元只能是“類”,只是我們說,某某類中的某某方法就是我們需要的邏輯。而在C#中,從最早開始就有“委托”這個東西可用來承載一段邏輯。與其為每種情況定義一個特定的Specification類,讓那個Spcification類去訪問外部資源(即建立依賴),不如我們將這個類中唯一需要的邏輯給準備好,各種依賴直接通過委托由編譯器自動保留,然后直接注入到一個“通用”的類中。很關鍵的是,這樣在編程方面也非常容易。

      至于原本ISpecification<T>中的And,Or,Not方法,我們可以將它們提取成擴展方法。有朋友說,既然有了擴展方法,那么對于一些不需要訪問私有成員/狀態的方法,都應該提取到實體的外部,避免“污染”實體。不過我不同意,在我看來,到底是用實例方法還是擴展方法,還是個根據職責和概念而一定的。我在這里打算使用擴展的目的,是因為And,Or,Not并非是一個Specification對象的邏輯,并不是一個Specification對象說,“我要去And另一個”,“我要去Or另一個”,或者“我要造……取反”。就好比二元運算符&&、||、或者+、-,左右兩邊的運算數字有主次之分嗎?沒有,它們是并列的。因此,我選擇使用額外的擴展方法,而不是將這些職責交給某個Specification對象:

      public static class SpecificationExtensions
      {
          public static ISpecification<T> And<T>(
              this ISpecification<T> one, ISpecification<T> other)
          {
              return new Specification<T>(candidate =>
                  one.IsSatisfiedBy(candidate) && other.IsSatisfiedBy(candidate));
          }
      
          public static ISpecification<T> Or<T>(
              this ISpecification<T> one, ISpecification<T> other)
          {
              return new Specification<T>(candidate =>
                  one.IsSatisfiedBy(candidate) || other.IsSatisfiedBy(candidate));
          }
      
          public static ISpecification<T> Not<T>(this ISpecification<T> one)
          {
              return new Specification<T>(candidate => !one.IsSatisfiedBy(candidate));
          }
      }
      

      此外,使用擴展方法的好處在于,如果我們想要加一個邏輯運算(如“異或”),那么是不需要修改接口的。修改接口是一件勞民傷財的事情。

      至此,我們使用Specification對象就容易多了,因為不需要為每段邏輯創建一個獨立的ISpecification<T>類型。但是,其實還有更簡單的:直接使用委托。既然整個Specificaiton對象的邏輯可以使用一個委托直接表示,那為什么我們還需要一個“外殼”呢?不如直接使用這樣的委托類型:

      public delegate bool Spec<T>(T candicate);

      當然,您也可以直接使用Func<T, bool>。我在這里創建Spec的目的,是因為我想“明確”這里其實是一個Specification,而不是一個普通的“接受T作為參數,返回bool的方法”。于是現在,我們便可以用這樣的擴展方法來編寫And,Or和Not:

      public static class SpecExtensions
      {
          public static Spec<T> And<T>(this Spec<T> one, Spec<T> other)
          {
              return candidate => one(candidate) && other(candidate);
          }
      
          public static Spec<T> Or<T>(this Spec<T> one, Spec<T> other)
          {
              return candidate => one(candidate) || other(candidate);
          }
      
          public static Spec<T> Not<T>(this Spec<T> one)
          {
              return candidate => !one(candidate);
          }
      }
      

      用它來編寫上次的示例便容易多了:

      static Spec<int> MorePredicate(Spec<int> original)
      {
          return original.Or(i => i > 0);
      }
      
      static void Main(string[] args)
      {
          var array = Enumerable.Range(-5, 10).ToArray();
          var oddSpec = new Spec<int>(i => i % 2 == 1);
          var oddAndPositiveSpec = MorePredicate(oddSpec);
      
          foreach (var item in array.Where(i => oddAndPositiveSpec(i)))
          {
              Console.WriteLine(item);
          }
      }
      

      由于有C#的擴展方法和委托,在C#中使用Specification模式比之前要容易許多。不過,在某些時候,我們可能還是需要老老實實按照標準來做。創建獨立的Specification對象的好處是在一個單獨的地方內聚地封裝了一段邏輯,因此適合較集中,較“重”的邏輯,而“委托”則適合輕便的實現。委托的另一個優勢是使用方便,但它的缺點便是難以“靜態表示”。如果您在使用Specification模式時,需要根據外部配置來決定進行何種組裝,那么可能只有為每種邏輯創建獨立的Specification對象了。此外,使用委托還有一個“小缺點”,即它可能會“不自覺”地提升對象的生命周期,可能會形成一些延遲方面的陷阱。

      當然,我并不是說獨立Specification對象就不會造成生命周期延長——只要功能實現一樣,各方面也應該是相同的。只不過獨立的Specificaiton對象給人一種“正式”而“隆重”的感覺,容易讓人警覺,因而緩解了這方面問題。

      不過還有一個問題我們還沒有解決——我們現在組裝的是委托或Specification對象,但如果我們需要組裝一個表達式樹,組裝完畢后交給如LINQ to SQL使用,又該怎么做呢?我們的“下”便會設法解決這個問題。

      主站蜘蛛池模板: 国产高清在线不卡一区| 国产亚洲精品日韩av在| 亚洲综合视频一区二区三区| 性做久久久久久久久| 人妻无码| 久久亚洲精品情侣| 国产人与zoxxxx另类| 久99久热这里只有精品| 国产片一区二区三区视频| 国产精品乱一区二区三区| 国产精品久久久久久久久软件| 亚洲人成网线在线播放VA| 国产精品福利午夜久久香蕉| 成人国产精品日本在线观看| 午夜国产精品福利一二| 精品一区二区久久久久久久网站| 一级片免费网站| 搡老熟女老女人一区二区| 亚洲不卡一区三区三区四| 久久精品天天中文字幕人妻| 河北真实伦对白精彩脏话| 国产一卡2卡三卡4卡免费网站| 普兰县| 久久人妻精品国产| 国产无遮挡猛进猛出免费软件| 亚洲中文久久久精品无码| 四虎成人精品无码| 日本丰满熟妇videossexhd| AV人摸人人人澡人人超碰| 成人亚洲一区二区三区在线| 成在线人免费| 国产午夜伦伦午夜伦无码| 少妇被无套内谢免费看| 久久精品国产99久久久古代| 男人狂桶女人出白浆免费视频| 国产玖玖视频| 国产精品天干天干综合网| 热99久久这里只有精品| 7m精品福利视频导航| 国产自产一区二区三区视频| 久本草在线中文字幕亚洲|