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

本文关键字:其他 解决方案 是什么 规则 | 更新日期: 2023-09-27 18:19:55

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

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

规则列表是使用DI框架自动发现的,并且不是预先固定的。

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

我考虑的解决方案:

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

    Pro:易于理解和实现
    违反:我需要知道/猜测原始规则的优先级。不清楚哪个优先级优先(1或1000)?对于特定情况不适用的情况,需要一些"不在乎"的规则结果。

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

    Pro:明确声明您想要实现的目标
    矛盾:需要显式引用原始规则。排序逻辑会很复杂。对于特定情况不适用的情况,需要一些"不在乎"的规则结果。

还有其他更好的选择吗?

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

我认为这在很大程度上取决于项目的范围以及您需要的松散耦合程度。我围绕业务规则做了很多工作,它们需要尽可能具有可扩展性。如果有哪怕是最少量的规则,或者它们的排序非常复杂,我也不会把自己束缚在有序规则系统中。我认为自动发现/连接规则绝对是最好的选择。

在我看来,这种情况的关键是,一般的案例规则是,而不是,因为缺乏与其范围相关的逻辑。一般案例规则必须具有与特定案例规则一样具体的范围逻辑。它们可能在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<>));
        });
    }
}

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