2012-01-09 84 views
7

我想打一個簡單的驗證系統,對某些類型的對象,基本上以下規則設計的其他解決方案是什麼?

public interface IMyClassRule { 
    bool IsValid(MyClass obj, Context someAdditionalData) 
} 

規則列表是自動發現使用DI框架,而不是事先固定的。

比方說,我有一個VeryGeneralDefaultRuleAboutAllObjects : IMyClassRuleSpecificCaseWhenGeneralRuleDoesNotApply : IMyClassRule。我如何以通用的方式處理此解決方案(基本上允許在某些情況下通過任何其他規則覆蓋任何規則)?

解決方案我認爲:

  1. 的規則或規則的數字優先級導致

    :簡單地理解和執行。
    對比:我需要知道/猜測原始規則的優先級。不清楚哪個優先級是第一個(1或1000)?對於特定情況不適用的情況,需要一些「不關心」規則結果。基於

  2. 類型優先級(基本.Before<VeryGeneralRule>

    :特別聲明要達到什麼目的。
    對比:需要明確引用原始規則。排序邏輯將變得複雜。對於特定情況不適用的情況,需要一些「不關心」規則結果。

還有其他/更好的選擇嗎?

+1

非常惱人的問題。我已經討論了這個問題幾個小時了,還沒有找到一個令人滿意的解決方案。 – CodesInChaos 2012-01-09 23:00:41

+2

考慮放棄自動發現並按優先級順序手動創建中央規則列表。 – CodesInChaos 2012-01-09 23:27:42

+0

看看Web規則的概念(http://rule.codeeffects.com)。我認爲你正在尋找類似於他們所做的事情。 – Kizz 2012-01-09 23:35:42

回答

0

如何在規則實例中添加註入某些條件的功能,例如,IRuleApplicability界面的實例。您可以將它與類似於#2的內容相結合,並在應用規則之前使用所有規則的基類來檢查適用性。

2

我想這很大程度上取決於項目的範圍,以及您需要的鬆散耦合程度。我在業務規則方面做了很多工作,他們需要儘可能地擴展。如果規則數量微乎其微,或者它們的排序甚至非常複雜,我都不會將自己與有序的規則系統聯繫起來。我認爲規則的自動發現/佈線絕對是這裏的方法。

在我看來,這種情況的關鍵是,一般情況下的規則是而不是,這是由於缺少與其範圍相關的邏輯定義的。一般案例規則必須具有與特定案例規則相同的範圍邏輯。他們可能在100次的範圍內99次,但他們仍然需要具有特定的範圍邏輯。

以下是我如何處理這個問題。我並不滿意將WithinScope()直接附加到IRule,但考慮到您正在考慮一個序列列表,我假設這個邏輯要麼是可管理的,要麼是相對靜態的,或者您可以爲該邏輯注入一個委託。

框架接口

public interface IRule<in T>{ 
    bool IsValid(T obj); 
    bool WithinScope(); 
} 

public interface IValidator<in T>{ 
    bool IsValid(T obj); 
} 

public interface IRuleFactory<in T>{ 
    IEnumerable<IRule<T>> BuildRules(); 
} 

通用驗證和規則廠

public class GenericValidator<T> : IValidator<T> 
{ 
    private readonly IEnumerable<IRule<T>> _rules; 

    public GenericValidator(IRuleFactory<T> ruleFactory){ 
     _rules = ruleFactory.BuildRules(); 
    } 

    public bool IsValid(T obj){ 
     return _rules.All(p => p.IsValid(obj)); 
    } 
} 

public class GenericRuleFactory<T> : IRuleFactory<T> 
{ 
    private readonly IEnumerable<IRule<T>> _rules; 

    public GenericRuleFactory(IEnumerable<IRule<T>> rules){ 
     _rules = rules; 
    } 

    public IEnumerable<IRule<T>> BuildRules(){ 
     return _rules.Where(x => x.WithinScope()); 
    } 
} 

樣品規則

public class VeryGeneralDefaultRuleAboutAllObjects : IRule<IMyClass> 
{ 
    private readonly Context _context; 

    public VeryGeneralDefaultRuleAboutAllObjects(Context context){ 
     _context = context;  
    } 

    public bool IsValid(IMyClass obj){ 
     return !obj.IsAllJackedUp; 
    } 

    public bool WithinScope(){ 
     return !_context.IsSpecialCase; 
    } 
} 

public class SpecificCaseWhenGeneralRuleDoesNotApply : IRule<IMyClass> 
{ 
    private readonly Context _context; 

    public VeryGeneralDefaultRuleAboutAllObjects(Context context){ 
     _context = context;  
    } 

    public bool IsValid(IMyClass obj){ 
     return !obj.IsAllJackedUp && _context.HasMoreCowbell; 
    } 

    public bool WithinScope(){ 
     return _context.IsSpecialCase; 
    } 
} 

IoC的接線(使用StructureMap)

public static class StructureMapBootstrapper 
{ 
    public static void Initialize() 
    { 
     ObjectFactory.Initialize(x => 
     { 
      x.Scan(scan => 
      { 
       scan.TheCallingAssembly(); 
       scan.AssembliesFromApplicationBaseDirectory(); 
       scan.AddAllTypesOf(typeof (IRule<>)); 
      }); 

      x.For(typeof(IValidator<>)) 
       .Use(typeof(GenericValidator<>)); 

      x.For(typeof(IRuleFactory<>)) 
       .Use(typeof(GenericRuleFactory<>)); 
     }); 
    } 
} 
+0

我最近實現了一些看起來很像這樣的東西,減去了更復雜的StructureMap佈線。我喜歡這個答案,因爲它證實了我所做的至少被社區中的另一個人認爲是理智的。 – 2012-02-16 11:48:49

相關問題