验证错误层次结构设计
本文关键字:结构设计 层次 错误 验证 | 更新日期: 2023-09-27 18:26:36
在我们的系统中,我们有一个实体Product
,它可能具有各种自定义属性。一组属性可能因产品而异,并且存储在类型为List<Property>
的字段中。属性是不同类型的(字符串、int、double),可能具有一些特殊特性,例如,它们可能是多值的,可能是特定范围的值,也可能是给定列表中的值等。属性的值始终包含在字符串字段Value
中。
现在,我目前的问题是实现这些属性的验证,我有点纠结于在验证结果的部分表示中应该采取什么方法。我必须满足的要求:-验证的结果将被其他应用层使用,因此生成的API应该清晰且易于使用-每个错误都应该有一个不同的表示-API的用户应该有足够的信息来理解错误细节(例如,对于范围错误,应该向他们提供最小可能值、最大可能值和实际值)
以下是我迄今为止考虑过的方法:
-
类层次结构有一个基本抽象类
ValidationError
,每个特定的错误都会反映在继承的类中。如果error有任何细节,那么相应的类将有必要的字段来存储所有信息。示例:public abstract class ValidationError { // common fields and methods, if any } public class IncorrectFormatValidationError : ValidationError { // just empty class, nothing to add here } public class RangeValidationError : ValidationError { public object MinValue { get; set; } public object MaxValue { get; set; } }
这种方法对我来说似乎是多余的,因为实际上有各种各样的空类。此外,使用这样的API似乎并不正确(
if (typeof(error) == typeof(RangeValidationError))
-胡说八道!)。然而,这是我想到的第一件事。 -
错误枚举以及必要时的类层次结构所有错误都用枚举表示。在大多数情况下使用一个类
ValidationError
,当特定错误需要额外信息时,将创建继承器,基本上与第一种方法相同。示例:public enum ValidationErrors { IncorrectFormat, ValueNotWithinRange, ... } public class ValidationError { public ValidationErrors ErrorType { get; set; } public ValidationError(ValidationErrors type) { this.ErrorType = type; ... } // common fields and methods, if any } public class RangeValidationError : ValidationError { public object MinValue { get; set; } public object MaxValue { get; set; } public RangeValidationError(object minValue, object maxValue) : base(ValidationErrors.ValueNotWithinRange) { ... } }
这种方法看起来要好得多,但也有缺点。最大的一个问题是,作为API用户,我们无法保证当我们有
ValueNotWithinRange
类型的错误时,我们正在处理RangeValidationError
类型的类,如果我们没有,我们如何处理它?我想有一些设计性的功能,甚至可以防止这种情况的存在,因为我不是开发API的人。这种方法的另一个问题是,如果大多数错误最终都需要一些额外的信息,我们最终会得到相同的1号蟑螂。
有人对这两种方法有什么想法可以分享,或者建议一种更好的方法吗?如有任何回应,我将不胜感激。提前谢谢。
退一步重新思考整个"表示验证错误的多个类"方法可能是个好主意,因为它几乎可以保证您已经有了验证器的层次结构。
任何验证错误都可以完美地指定给:
- 未能接受属性值的验证器
- 物业名称
- 未能验证的值
任何进一步的信息(例如,范围的限制、不匹配的正则表达式)都已经存在于验证器实例上,并且可以通过它进行访问。
那么,如果只有一个看起来像这样的验证错误类:呢
public sealed class ValidationError
{
public Validator Validator { get; set; }
public string PropertyName { get; set; }
public object AttemptedValue { get; set; }
}
您可能需要了解FluentValidation之类的内容。它重量轻、直观,涵盖了许多验证场景。
如果您对FluentValidation使用的验证结果不满意,您可以始终将它们封装在自己的自定义验证错误类中。至少你可以免费获得很多基本功能。