Бизнес-объекты, валидация и исключения - PullRequest
37 голосов
/ 18 сентября 2008

Я читал несколько вопросов и ответов относительно исключений и их использования. Кажется, существует твердое мнение о том, что исключения должны выдвигаться только для исключительных, необработанных случаев. Так что это заставило меня задуматься, как валидация работает с бизнес-объектами.

Допустим, у меня есть бизнес-объект с геттерами / сеттерами для свойств объекта. Допустим, мне нужно проверить, что значение составляет от 10 до 20. Это бизнес-правило, поэтому оно принадлежит моему бизнес-объекту. Так что, мне кажется, это означает, что код проверки у меня в установщике. Теперь у меня есть пользовательский интерфейс, связанный со свойствами объекта данных. Пользователь вводит 5, поэтому правило должно завершиться сбоем, и пользователю не разрешается выходить из текстового поля. , Пользовательский интерфейс привязан к свойству, поэтому метод вызова будет вызван, правило проверено и не выполнено. Если бы я вызвал исключение из моего бизнес-объекта, чтобы сказать, что правило не выполнено, пользовательский интерфейс подхватит это. Но это, кажется, идет вразрез с предпочтительным использованием исключений. Учитывая, что это сеттер, у вас не будет «результата» для сеттера. Если я установлю другой флаг на объекте, это будет означать, что пользовательский интерфейс должен проверять этот флаг после каждого взаимодействия с пользовательским интерфейсом.

Так как же должна работать проверка?

Редактировать: я, вероятно, использовал здесь упрощенный пример. Нечто похожее на проверку диапазона может легко обрабатываться пользовательским интерфейсом, но что, если проверка была более сложной, например, бизнес-объект вычисляет число на основе входных данных, и если это вычисленное число выходит за пределы диапазона, его следует отклонить. Это более сложная логика, которой не должно быть в интерфейсе пользователя.

Существует также рассмотрение дополнительных данных, введенных на основе уже введенного поля. Например, мне нужно ввести элемент в заказ, чтобы получить определенную информацию, такую ​​как запас в наличии, текущая стоимость и т. д. Пользователь может потребовать эту информацию для принятия решения о дальнейшем поступлении (например, сколько единиц на заказ) или она может потребоваться для для дальнейшей проверки. Должен ли пользователь иметь возможность вводить другие поля, если элемент недействителен? Какой в ​​этом смысл?

Ответы [ 18 ]

3 голосов
/ 29 декабря 2008

Как упоминалось в статье Пола Стоувелла , вы можете реализовать безошибочную проверку в ваших бизнес-объектах, реализовав интерфейс IDataErrorInfo. Это позволит пользователю уведомлять об ошибках WinForm's ErrorProvider и привязка WPF с правилами проверки . Логика для проверки свойств ваших объектов хранится в одном методе, а не в каждом из ваших методов получения свойств, и вам не обязательно прибегать к таким фреймворкам, как CSLA или Validation Application Block.

Что касается запрета пользователю изменять фокусировку из текстового поля: Прежде всего, это обычно не лучшая практика. Пользователь может захотеть заполнить форму не по порядку, или, если правило проверки зависит от результатов нескольких элементов управления, пользователю может потребоваться заполнить фиктивное значение только для того, чтобы выйти из одного элемента управления и установить другой элемент управления. Тем не менее, это можно реализовать, установив для свойства AllowValidate формы значение по умолчанию, EnableAllowFocusChange и подписавшись на событие Control.Validating:

    private void textBox1_Validating(object sender, CancelEventArgs e)
    {
        if (textBox1.Text != String.Empty)
        {
            errorProvider1.SetError(sender as Control, "Can not be empty");
            e.Cancel = true;
        }
        else
        {
            errorProvider1.SetError(sender as Control, "");
        }
    }

Использование правил, хранящихся в бизнес-объекте, для этой проверки немного сложнее, поскольку событие Validating вызывается до изменения фокуса и обновления бизнес-объекта с привязкой к данным.

1 голос
/ 18 сентября 2008

По моему опыту, правила проверки редко бывают универсальными для всех экранов / форм / процессов в приложении. Подобные сценарии распространены: на странице добавления может быть нормальным, чтобы объект Person не имел фамилии, но на странице редактирования он должен иметь фамилию. В этом случае я пришел к выводу, что проверка должна происходить вне объекта или правила должны быть внедрены в объект, чтобы правила могли изменяться в зависимости от контекста. Valid / Invalid должен быть явным состоянием объекта после проверки или тем, которое может быть получено путем проверки коллекции на наличие сбойных правил. Неудачное бизнес-правило не является исключением IMHO.

1 голос
/ 18 сентября 2008

Бросок исключения в вашем случае - это нормально. Вы можете рассматривать случай как истинное исключение, потому что что-то пытается установить целое число в строку (например). Из-за недостаточного знания бизнес-правил ваши взгляды означают, что они должны рассмотреть этот случай, за исключением случая, и вернуть его обратно в представление.

Независимо от того, проверяете ли вы свои входные значения перед тем, как отправлять их на бизнес-уровень, зависит от вас, я думаю, что если вы будете следовать одному и тому же стандарту во всем приложении, вы получите чистый и читаемый код.

Вы можете использовать среду Spring, как указано выше, просто будьте осторожны, так как большая часть связанного документа указывала на написание кода, который не является строго типизированным, т.е. вы можете получить ошибки во время выполнения, которые вы не можете обнаружить во время компиляции. Я стараюсь избегать этого как можно больше.

То, как мы делаем это здесь в настоящее время, заключается в том, что мы берем все входные значения с экрана, связываем их с объектом модели данных и генерируем исключение, если значение содержит ошибку.

1 голос
/ 18 сентября 2008

Вы можете рассмотреть подход, принятый средой Spring . Если вы используете Java (или .NET), вы можете использовать Spring как есть, но даже если нет, вы все равно можете использовать этот шаблон; вам просто нужно написать свою собственную реализацию.

1 голос
/ 18 сентября 2008

Рассматривали ли вы создание события в установщике, если данные неверны? Это позволило бы избежать проблемы создания исключения и избавило бы от необходимости явно проверять объект на наличие «недопустимого» флага. Вы можете даже передать аргумент, указывающий, какое поле не прошло проверку, чтобы сделать его более пригодным для повторного использования.

Обработчик события должен иметь возможность позаботиться о возвращении фокуса на соответствующий элемент управления, если это необходимо, и он может содержать любой код, необходимый для уведомления пользователя об ошибке. Кроме того, вы можете просто отказаться от подключения обработчика событий и при необходимости игнорировать ошибку проверки.

0 голосов
/ 18 сентября 2008

Если входные данные выходят за пределы бизнес-правила, реализуемого бизнес-объектом, я бы сказал, что этот случай не обрабатывается бизнес-объектом. Поэтому я бы бросил исключение. Даже если в вашем примере установщик будет «обрабатывать» 5, бизнес-объект не будет.

Для более сложных комбинаций ввода требуется метод vaildation, иначе вы получите довольно сложные проверки, разбросанные повсюду.

По моему мнению, вам придется решить, какой путь выбрать, в зависимости от сложности разрешенного / запрещенного ввода.

0 голосов
/ 27 августа 2009

Я думаю, это зависит от того, насколько важна ваша бизнес-модель. Если вы хотите пойти по пути DDD, ваша модель - самая важная вещь. Следовательно, вы хотите, чтобы он всегда был в действительном состоянии.

По моему мнению, большинство людей пытаются сделать слишком много (общаться с представлениями, сохранить в базе данных и т. Д.) С объектами домена, но иногда вам нужно больше слоев и лучшее разделение интересов, т. Е. Один или несколько Посмотреть модели. Затем вы можете применить проверку без исключений к вашей модели представления (проверка может быть разной для разных контекстов, например, веб-сервисов / веб-сайта / и т. Д.) И сохранить проверки исключений внутри вашей бизнес-модели (чтобы предотвратить повреждение модели). Вам потребуется один (или более) слой службы приложений, чтобы сопоставить вашу модель представления с вашей бизнес-моделью. Бизнес-объекты не должны быть загрязнены атрибутами проверки, часто связанными с конкретными структурами, например, NHibernate Validator.

0 голосов
/ 18 сентября 2008

По моему мнению, это пример, когда выбрасывать исключение можно. Возможно, ваше свойство не имеет контекста для исправления проблемы, так как такое исключение необходимо, и вызывающий код должен по возможности справиться с ситуацией.

...