Валидация на среднем уровне
Я хочу сделать проверку моего бизнес-кода. Я думаю о 2 способах сделать это.
Во-первых, выполните проверку на мои установщики свойств класса следующим образом
class Student{
public string Name{
get { return _name; }
set {
if (value.IsNullOrEmpty) throw exception ...
}
}
}
Теперь, проблема с этим подходом состоит в том, что код проверки запускается каждый раз, когда назначается Имя, которое нам может не понадобиться, например, при заполнении его данными из БД.
Два, которые я предпочитаю, помещают статические методы в эти классы сущностей, как
class Student {
public **static** void ValidateName(**string name**) {
if (string.IsNullorEmpty(name))
{
throw ...
}
...
}
Обратите внимание, что я использую статический метод вместо метода экземпляра, как
class Student{
public void Validate() {
// validation logic on instance properties
if (string.IsNullorEmpty(Name))
{
throw ...
}
...
}
потому что я не всегда передаю объект Student, я получаю примитивные типы, такие как имя строки, часто передаваемое в метод, например
public static FindStudentByName(string name)
{
// here I want to first do validation
Student.ValidateName(name);
// query DB
...
}
Если меня зачислили в студенческий объект, то, конечно, я могу сделать
public static AddStudent(Student s)
{
// call the instance method
s.Validate();
}
Теперь я хотел бы сделать вещи очень простыми, поэтому я не хочу использовать один из следующих подходов
Используйте атрибуты для свойств, например [StringLength(25)].
Во-первых, поскольку это требует рефлексии и влияет на производительность, существуют хитрости, чтобы снизить производительность, но опять же, я хочу, чтобы она была проще, чем лучше.
Во-вторых, я хочу, чтобы мой сайт мог работать в Medium Trust. Для размышления, насколько я понимаю, требуется полное доверие.
Используйте любой из блоков валидации, например MS. Корпоративная библиотека и т. Д. Найдена на CodePlex.
Теперь я хочу узнать ваше мнение об этом,
Каковы некоторые из потенциальных проблем с подходом, с которым я иду?
Будет ли этот подход работать лучше, более читабельным, легче поддерживать, чем другие подходы?
Как вы делаете проверку на среднем уровне?
Спасибо большое!
Ray.
3 ответа
Я выполняю валидацию домена на среднем уровне с помощью механизма правил, очень похожего на тот, о котором написано здесь. В проекте друга используется подход, аналогичный тому, который вы предлагаете в последнем примере, и конечный результат не поддерживается (хрупкий, трудно реализуемый универсальный пользовательский интерфейс проверки). Подход с помощью механизма правил можно поддерживать, поскольку он локализует все правила проверки и сохранения в одном хорошо организованном месте и имеет каждое правило как полноценный класс, но предоставляет проверку для классов домена, аналогичную предложенной вами. Некоторым людям нравится динамическая компиляция, поэтому они сохраняют их в базе данных для высокого уровня конфигурации после развертывания; в моем случае они мне нравятся, когда проверяется время компиляции, поэтому есть определения правил с лямбдами в статическом классе.
Я знаю, что это не соответствует тому, что вы хотите сделать, но спросить, как я это сделаю, и сказать, что другие подходы недостаточно просты, это все равно, что сказать: "Как вы можете написать надежный код, я хочу, чтобы он был простым, поэтому модульных тестов не может быть и речи ". С моей точки зрения, каждое правило - это отдельный класс, потому что его легче поддерживать и документировать, хотя и сложнее реализовать.
Подход, который вы предлагаете, указывает на то, что набор проверки не должен применяться всегда. Что в порядке. Я видел множество правил и проверок, которые мы хотим "большую часть времени", но не всегда. Итак, возникает вопрос "когда вы хотите, чтобы эти проверки применялись"?
Скажем, что, например, у вас есть некоторые проверки, которые вы всегда хотите применить, и некоторые, которые вы хотите проверять только тогда, когда... я не знаю... вы собираетесь сохранить в хранилище (базе данных). В этом случае проверки, которые применяются всегда, должны быть в свойствах (см. Подробнее об этом ниже), а проверки, которые применяются только тогда, когда вы собираетесь сохранить в хранилище, должны быть в методе (может быть назван в виде строки 'VerifyRulesForStorage'), который будет вызываться при необходимости (например, в середине вашего метода SaveToStorage).
Думаю, стоит рассмотреть одну вещь: дублирование, которое вы рискуете получить, если у вас одинаковая проверка по нескольким объектам. Будь то свойство или метод VerifyRulesForStorage, вполне вероятно, что у вас будет одна и та же проверка (например, String.IsNullOrEmpty, CheckItsANumber, CheckItsOneOfTheAcceptedValues и т. Д.) Во многих местах во многих классах. Конечно, вы можете решить эту проблему с помощью наследования (например, все ваши сущности наследуют от базового класса Entity, в котором есть методы, реализующие каждый тип проверки), или композиции (возможно, лучший подход, так что дерево классов ваших сущностей управляется другим, более уместны соображения, например: все ваши сущности имеют объект Validator, который реализует все эти проверки). В любом случае, вы можете захотеть держаться подальше от статических методов, потому что они, как правило, создают проблемные ситуации, если вы управляем тестом (есть способы обойти, когда это необходимо).
В нашей системе у нас фактически есть метаданные, описывающие правила валидации. Имя свойства класса используется для получения правильных метаданных, которые затем сообщают системе, какие правила применять. Затем у нас есть объект-валидатор, который создает экземпляр правильного типа объекта для фактической проверки с помощью фабрики (например, у нас есть один класс, реализующий правило IsRequiredString, другой, реализующий правило IsNumber и т. Д. И т. Д.). Звучит как сложность, но в такой системе, как наша, это определенно стоило того.
Наконец, готовые библиотеки могут быть хорошей альтернативой. В нашем случае они были не из-за особых требований, которые у нас были - но в целом... есть преимущества в использовании колеса, которое кто-то другой разработал (и будет поддерживать), по сравнению с созданием собственного (поверьте мне, я люблю восстанавливать колеса, когда я может.. я просто говорю, что есть случаи, когда каждый подход лучше другого).
Вариант два - это то, что на самом деле не требует проверки, по крайней мере, если вы не вызовете validate вручную. Поэтому потребители ваших объектов могут нарушать правила.
Лично я бы пошел с чем-то похожим на ваш первый пример, так как он гарантирует, что ВСЕ данные действительны. это дополнительная проверка на стороне БД, но из того, что я заметил, как правило, нет ничего особенного.