业务对象、验证和异常 [英] Business Objects, Validation And Exceptions

查看:29
本文介绍了业务对象、验证和异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在阅读一些关于异常及其使用的问题和答案.似乎是一种强烈的意见,即只应为异常、未处理的情况引发异常.这让我想知道验证如何与业务对象一起使用.

假设我有一个业务对象,其中包含对象属性的 getter/setter.假设我需要验证该值是否在 10 到 20 之间.这是一个业务规则,因此它属于我的业务对象.所以这对我来说似乎暗示验证代码在我的 setter 中.现在我将 UI 数据绑定到数据对象的属性.用户输入5,所以规则需要失败,并且不允许用户移出文本框..UI 数据绑定到属性,因此将调用 setter,检查规则并失败.如果我从我的业务对象中提出一个异常来说明规则失败,UI 会选择它.但这似乎与例外的首选用法背道而驰.鉴于它是一个二传手,你不会真的有二传手的结果".如果我在对象上设置另一个标志,则意味着 UI 必须在每次 UI 交互后检查该标志.

那么验证应该如何工作?

我可能在这里使用了一个过于简化的例子.UI 可以轻松处理上面的范围检查之类的事情,但是如果验证更复杂,例如业务对象根据输入计算一个数字,如果计算出的数字超出范围,则应拒绝该数字.这是更复杂的逻辑,不应出现在 UI 中.

还需要考虑根据已输入的字段输入更多数据.例如,我必须在订单上输入一个项目才能获得某些信息,如库存、当前成本等.用户可能需要这些信息来决定进一步输入(例如要订购多少件),或者可能需要它以进行进一步验证.如果项目无效,用户是否应该能够输入其他字段?重点是什么?

解决方案

您想深入了解 的非凡工作Paul Stovell 关于数据验证.他曾在这篇文章中总结了自己的想法.我碰巧分享了他对此事的看法,我在 我自己的库.

用 Paul 的话来说,这里是在 setter 中抛出异常的缺点(基于 Name 属性不应为空的示例):

<块引用>
  • 有时您可能确实需要一个空名称.例如,作为 创建帐户" 表单的默认值.
  • 如果您在保存之前依靠它来验证任何数据,您将错过数据已经无效的情况.我的意思是,如果您从数据库中加载一个名称为空的帐户并且不更改它,您可能永远不会知道它是无效的.
  • 如果您不使用数据绑定,则必须使用 try/catch 块编写大量代码以向用户显示这些错误.在用户填写表单时尝试在表单上显示错误变得非常困难.
  • 我不喜欢为非异常的事情抛出异常.用户将帐户名称设置为 "Supercalafragilisticexpialadocious" 不是例外,而是错误.当然,这是个人的事情.
  • 获取所有已违反规则的列表变得非常困难.例如,在某些网站上,您会看到诸如必须输入姓名.必须输入地址.必须输入电子邮件"之类的验证消息.要显示它,您将需要很多 try/catch 块.

这里是替代解决方案的基本规则:

<块引用>

  1. 拥有无效的业务对象并没有错,只要您不尝试保留它.
  2. 应该可以从业务对象中检索任何和所有违反的规则,以便数据绑定以及您自己的代码可以查看是否存在错误并适当地处理它们.

I’ve been reading a few questions and answers regarding exceptions and their use. Seems to be a strong opinion that exceptions should be raised only for exception, unhandled cases. So that lead me to wondering how validation works with business objects.

Lets say I have a business object with getters/setters for the properties on the object. Let’s say I need to validate that the value is between 10 and 20. This is a business rule so it belongs in my business object. So that seems to imply to me that the validation code goes in my setter. Now I have my UI databound to the properties of the data object. The user enters 5, so the rule needs to fail and the user is not allowed to move out of the textbox. . The UI is databound to the property so the setter is going to be called, rule checked and failed. If I raised an exception from my business object to say the rule failed, the UI would pick that up. But that seems to go against the preferred usage for exceptions. Given that it’s a setter, you aren’t really going to have a ‘result’ for the setter. If I set another flag on the object then that would imply the UI has to check that flag after each UI interaction.

So how should the validation work?

Edit: I've probably used an over-simplified example here. Something like the range check above could be handled easily by the UI but what if the valdation was more complicated, e.g. the business object calculates a number based on the input and if that calculated number is out of range it should be recjected. This is more complicated logic that should not be in th UI.

There is also the consideration of further data entered based on a field already entered. e.g.I have to enter an item on the order to get certain informaion like stock on hand, current cost, etc. The user may require this information to make decisions on further entry (liek how many units to order) or it may be required in order for further validation to be done. Should a user be able to enter other fields if the item isn't valid? What would be the point?

解决方案

You want to delve a bit in the remarkable work of Paul Stovell concerning data validation. He summed up his ideas at one time in this article. I happen to share his point of view on the matter, which I implemented in my own libraries.

Here are, in Paul's words, the cons to throwing exceptions in the setters (based on a sample where a Name property should not be empty) :

  • There may be times where you actually need to have an empty name. For example, as the default value for a "Create an account" form.
  • If you're relying on this to validate any data before saving, you'll miss the cases where the data is already invalid. By that, I mean, if you load an account from the database with an empty name and don't change it, you might not ever know it was invalid.
  • If you aren't using data binding, you have to write a lot of code with try/catch blocks to show these errors to the user. Trying to show errors on the form as the user is filling it out becomes very difficult.
  • I don't like throwing exceptions for non-exceptional things. A user setting the name of an account to "Supercalafragilisticexpialadocious" isn't an exception, it's an error. This is, of course, a personal thing.
  • It makes it very difficult to get a list of all the rules that have been broken. For example, on some websites, you'll see validation messages such as "Name must be entered. Address must be entered. Email must be entered". To display that, you're going to need a lot of try/catch blocks.

And here are basic rules for an alternative solution :

  1. There is nothing wrong with having an invalid business object, so long as you don't try to persist it.
  2. Any and all broken rules should be retrievable from the business object, so that data binding, as well as your own code, can see if there are errors and handle them appropriately.

这篇关于业务对象、验证和异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆