2012-01-09 85 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

相关问题