验证策略

Pet*_*ris 9 c# design-patterns

我有一个包含许多类的业务模型,这个模型中的一些逻辑实体由许多不同的类组成(父子孙.)在这些不同的类中,我定义了不变的约束,例如复合的根应该有代码的值.

我目前每个类都实现了这样的接口......

public interface IValidatable
{
    IEnumerable<ValidationError> GetErrors(string path);
}
Run Code Online (Sandbox Code Playgroud)

如果未设置Code,则父级将添加验证错误,然后对每个子级执行GetErrors,这反过来会在每个子级上调用GetErrors.

现在,我需要为不同的操作验证不同的约束

  1. 应始终检查某些约束,因为它们是不变的
  2. 当我想在根上执行操作X时,应该检查一些约束.
  3. 执行操作Y时可能会检查一些其他约束.

我曾考虑在GetErrors方法中添加一个"Reason"参数,但由于某种原因,我无法完全理解这一点并不合适.我还考虑过创建一个访问者并有一个具体的实现来验证OperationX和另一个针对OperationY但不喜欢这个,因为一些约束检查需要多个操作但不是所有操作(例如,OperationX + OperationY需要一个Date但不是OperationZ)我不想复制检查的代码.

任何建议,将不胜感激.

Dan*_*ant 4

这里有一个绝缘问题,因为您的类负责进行自己的验证,但验证的性质取决于您正在执行的操作类型。这意味着类需要了解可以对其执行的操作类型,这在类和使用它们的操作之间创建了相当紧密的耦合。

一种可能的设计是创建一组并行的类,如下所示:

public interface IValidate<T>
{
    IEnumerable<ValidationError> GetErrors(T instance, string path);
}

public sealed class InvariantEntityValidator : IValidate<Entity>
{
    public IEnumerable<ValidationError> GetErrors(Entity entity, string path)
    {
        //Do simple (invariant) validation...
    }
}

public sealed class ComplexEntityValidator : IValidate<Entity>
{
    public IEnumerable<ValidationError> GetErrors(Entity entity, string path)
    {
        var validator = new InvariantEntityValidator();
        foreach (var error in validator.GetErrors(entity, path))
            yield return error;

        //Do additional validation for this complex case
    }
}
Run Code Online (Sandbox Code Playgroud)

您仍然需要解决如何将验证类与正在验证的各种类关联起来。听起来这应该以某种方式发生在操作级别,因为这是您知道需要进行什么类型的验证的地方。如果没有更好地理解您的架构,很难说。