以下规则设计的其他解决方案是什么?

时间:2012-01-09 22:48:34

标签: c# rules

我想为某类对象制作一个简单的验证系统,基本上是

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

使用DI框架自动发现规则列表,而不是事先修复。

假设我有VeryGeneralDefaultRuleAboutAllObjects : IMyClassRuleSpecificCaseWhenGeneralRuleDoesNotApply : IMyClassRule。如何以通用方式处理此解决方案(在某些情况下基本上允许通过任何其他规则覆盖任何规则)?

我考虑过的解决方案:

  1. 规则或规则结果的数字优先级

    Pro :易于理解和实施 反对:我需要知道/猜测原规则的优先级。不明显哪个优先(1或1000)?对于特定情况不适用的情况,需要一些“不关心”的规则结果。

  2. 基于类型的优先级(基本上为.Before<VeryGeneralRule>

    Pro :具体说明您想要达到的目标 Contra :需要明确引用原始规则。订购逻辑将很复杂。对于特定情况不适用的情况,需要一些“不关心”的规则结果。

  3. 还有其他/更好的选择吗?

2 个答案:

答案 0 :(得分:2)

我认为这很大程度上取决于项目的范围以及您需要的松散耦合程度。我围绕业务规则做了很多工作,他们需要尽可能地扩展。如果有最轻微的规则,或者它们的排序甚至是非常复杂的话,我也不会把自己绑在一个有序规则系统上。我认为规则的自动发现/接线绝对是这里的方法。

在我看来,这种情况的关键在于,一般案例规则是由缺少与其范围相关的逻辑定义的。一般案例规则必须具有与特定案例规则一样具体的范围逻辑。它们可能在100次中的范围99中,但它们仍然需要具有特定的范围逻辑。

以下是我接近这个的方法。我很不喜欢直接连接到IRule的WithinScope(),但考虑到你正在考虑一个序数列表,我假设逻辑是可管理的和相对静态的,或者你可以为该逻辑注入一个委托。

框架界面

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<>));
        });
    }
}

答案 1 :(得分:0)

如何在规则实例中添加注入某些条件的功能,例如IRuleApplicability接口的实例。您可以将其与类似于#2的内容组合,并在应用规则之前使用所有规则的基类来检查适用性。