В нашей системе у нас есть объект Product
, который может иметь различные пользовательские свойства. Набор свойств может отличаться от продукта к продукту и хранится в поле типа List<Property>
. Свойства имеют разные типы (строки, ints, double) и могут иметь некоторые особые характеристики, например. они могут быть многозначными, может быть значением определенного диапазона, значения из данного списка и т. д. Значение свойства всегда содержится в поле строки Value
.Иерархия ошибок проверки достоверности
Теперь моя текущая проблема заключается в реализации валидации этих свойств, и я отчасти зациклен на том, какой подход принять участие в эрпрезентации результатов проверки. Требования, которые мне необходимо выполнить: - Результаты проверки будут использоваться другими уровнями приложений, поэтому полученный API должен быть ясным и простым в использовании. . Каждая ошибка должна иметь отчетливое представление. - Пользователям API должно быть достаточно информация для понимания специфики ошибок (например, для ошибок диапазона они должны быть обеспечены с минимально возможной стоимостью, максимальным возможным значением и фактическим значением)
Здесь находятся подходы, я рассмотренные до сих пор:
Классы иерархия. Существует один базовый абстрактный класс
ValidationError
, и каждая конкретная ошибка будет отражена в унаследованном классе. Если ошибка имеет какие-либо особенности, соответствующий класс будет иметь необходимые поля для хранения всей информации. Пример: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, не можем гарантировать, что, когда у нас есть ошибка типа say
ValueNotWithinRange
, мы имеем дело с классом типаRangeValidationError
, а если нет, то как мы его обрабатываем? В то же время я хотел бы иметь некоторую функцию уровня дизайна, которая предотвратила бы даже такие ситуации, поскольку я не являюсь разработчиком API, который разрабатывает API. Еще одна проблема этого подхода заключается в том, что, если большинство ошибок будет в конечном итоге требует некоторой дополнительной информации, мы в конечном итоге с тем же номером aprroach 1.
кого-то есть мысли разделить на этих двух подходов или предложить лучший? Я буду очень признателен за любой ответ. Заранее спасибо.
В самом деле, вы избегаете дублирования иерархии таким образом, но вы также вводите дополнительное понижение абстрактного Validator. Я предлагаю изменить Validator в параметр типа. – Basilevs
@Basilevs: в любом случае (даже в иерархии ValidationError) необходимо будет использовать downcasting, если вам нужно получить доступ к членам, которые не присутствуют в корневой иерархии (например, свойства 'Min' и' Max'). Единственный способ - создать объект для динамического доступа к значениям свойств во время выполнения, что является моральным эквивалентом использования рефлексии и имеет одну и ту же основную проблему: потеря безопасности типа. – Jon
@ Jon, спасибо за ответ. Нет, пока у меня нет валидаторов. Все проверки выполняются несколькими методами уровня BL. Однако, может быть, стоит подумать об их введении? Но если это так, мы сталкиваемся с той же проблемой, что и для ошибок (которые описаны в вопросе), не так ли? – Andrei