2

假设我有一个巨大的输入表单,当然代表类。我需要将此输入加载到类的实例中。这个输入显然包含(一些非常复杂的验证)检查,显然逻辑层已经包含了那些输入验证。问题是我在用gui做什么。

我是否应该以一种非常丑陋的方式在 GUI 中重写所有这些验证?

或者我应该在逻辑层中编写一些静态方法,在 gui 和逻辑层中使用这些方法,但仍然创建验证自身的重复(首先 gui 验证自身,然后逻辑验证发送给它的内容)

或者我应该假设 gui 没问题,用 try 块包围使用逻辑层的相关代码,然后,如果抛出异常,通知用户有些事情是不正确的(不给他机会知道什么它是)

或者我应该公开异常,以这种方式向他公开参数、类和命名空间名称,他可能不会理解。

或者我应该为每个错误创建一个特殊的异常类,这样可以准确地告诉用户问题是什么,但可能会创建数百个可能的异常

还是我应该将它与一般异常分开,每个人都包括枚举描述错误的确切内容,然后捕获这些异常,并通过检查枚举告诉用户究竟是什么问题,但通过捕获所有不必要的异常使应用程序更重时间。

或者我应该(有人向我提供了这个,这不是我的想法,不要对我大喊大叫:D)来验证逻辑层中的输入,并且只在 gui 中检查它(似乎是我绝对可怕解决方案:D)

还有更重要的问题——我应该在哪里学习这些东西?通常我的直觉很好,但我不想不必要地发明轮子..(我很确定你每天都在轰炸这些基本的东西)。

非常感谢!

4

3 回答 3

3

当然,您应该验证用户输入。如果输入和验证逻辑像你说的那样复杂,那么在 GUI 中验证输入就更重要了,以一种让用户清楚预期值是什么的方式,如果有任何错误, 它们是什么。如果您可以建议如何解决这些错误,则可以加分!

它确实无助于用户查看异常和异常详细信息——所以尽量避免这种情况。

此外,由于您正在处理 GUI 中的输入验证,并且错误的输入是一种预期,并且并非真正与众不同,因此使用 Exceptions 不一定是一个好主意。一个简单的IsValid()方法来检查某事是否有效是可取的。我始终遵循“例外情况适用于特殊情况”的规则。

因此,如果您接受 GUI 中的验证是一件好事,那么下一个问题是:如何?

您说您已经进行了很多验证,但听起来您的验证逻辑不能单独使用。我一直觉得很有用的一种做法是将验证代码与其他业务逻辑分开。这允许您在适当的地方重用验证逻辑,在这种情况下,允许您在业务对象和 GUI 之间共享相同的验证逻辑。显然,有许多设计方法和框架可以做到这一点,但基本原则是“关注点分离”——保持验证逻辑分离,并使其可供使用。当您说“在逻辑层中编写一些静态方法,在 gui 和逻辑层中使用这些方法”时,您似乎在思考同样的问题,那

只是为了清楚起见——我并不是建议您将验证逻辑放在 GUI 本身中。相反,使验证逻辑可供 GUI 使用。唯一应该在 GUI 中的验证部分是从用户那里获取输入的部分(提交给验证)和显示验证结果的部分(给用户)。

编辑:

对于特定的设计理念,我不想听起来像个骗子,但最近我一直在使用领域驱动设计原则做更多的工作。我发现它工作得很好,它解决了您提出的许多问题。关于 SO 有几个问题,它们提供了关于它是什么以及一些资源在哪里的更多详细信息:

https://stackoverflow.com/questions/1353742/domain-driven-design-ddd-readings
什么是域驱动设计?

另外,在这里阅读: http ://www.lostechies.com/blogs/jimmy_bogard/archive/2009/02/15/validation-in-a-ddd-world.aspx

编辑2:

也是有用的(和相关的)阅读:业务对象、验证和异常

于 2009-10-17T05:35:03.853 回答
1

我刚刚在工作项目中完成了非常相似的事情。我有 3 个相当大的表格和一大堆代表所需数据的类。每个类都有一个 bool IsValid() 方法。

当用户单击保存按钮时,将调用一个方法,该方法从表单上的输入项构建所有类。每个属性都有非常简单的验证(类型、未设置的默认值等)。一旦所有的类都建立起来(形成一个树状结构 - 一个包含大量其他类的顶级类),就会在父级上调用 IsValid 方法,然后在其所有子级上调用 IsValid。

如果 IsValid 返回 False,则父级的 Errors 属性将设置为其所有未通过 IsValid 调用的子级的 Errors 属性。然后我在用户友好的视图中显示错误。

但是,在某些情况下,我需要在单击保存按钮之前验证某些标准,我为相关类提供了方法。

我真的认为您根本不应该在 GUI 类中进行验证。每个类都应负责自己的验证要求。但是,我认为使用 GUI 向用户提供有关表单的哪些区域需要的“提示”很好,例如使用更改事件来启用或禁用表单的某些部分。

我认为,一般来说,以不需要 GUI 的方式编写所有逻辑和类是个好主意。如果您想创建一个控制台前端而不是 Windows 窗体,该怎么办?您应该能够在不更改您已经拥有的商务课程的情况下将其中一个换成另一个。

于 2009-10-17T05:32:38.640 回答
0

这是一个很好的问题。将验证放在数据层的想法是一个经典的 OO 概念,但是当橡胶遇到道路时,它可能会很尴尬。我喜欢将实体的验证规则放入他们自己的类中以便可以重用的想法;但是,还有更多需要考虑。

我通常使用分层方法进行数据验证,顶层(表示层)包含最复杂和有用的代码。在中间层和数据层,验证的重点是验证断言并在遇到无效数据时抛出异常。这个想法是您希望表示层完全验证数据,但如果无效数据通过,您希望保护业务逻辑并提供良好的诊断。您绝对不想向用户显示原始异常,但最好保留异常信息以便您可以访问它。例如,您可以将异常跟踪写入日志文件和/或通过电子邮件将其发送给自己和/或在您认为用户可以处理的情况下在适当的上下文中将其显示给用户。

当您考虑数据验证的细节时,创建“知道”如何验证自身的对象的经典想法变得不像最初出现的那么有用。每一层验证都解决了一些不同的问题。即使底层业务规则驱动所有层的验证,对无效数据的响应也会因代码的上下文而异。主要区别在于,在表示层,你真的希望专注于与用户进行清晰的沟通,并在面对无效数据时创造良好的用户体验。应该将此代码内置到各个屏幕和控件中,这确实是有道理的。

绝对建议将简单的原子业务规则提炼成专用于验证的类中的简单函数或常量。您还可以按照您的建议将这些规则放入数据层类的静态函数中。主要的是只定义一次验证规则。例如,如果应用程序将一个值限制在 10 到 100 之间,那么常量 10 和 100 在您的代码中应该只出现一次。但是这些常量或执行范围验证的简单函数将在不同层的多个验证函数中使用。

在相关主题上,还可以定义包含只有验证常量和简单验证函数的类的验证程序集。然后可以将这些验证程序集加载到 SQLCLR 中并用于数据库层验证。通过这种方式,相同的验证定义可以跨越整个系统一直到数据库层。

于 2009-10-17T07:15:40.747 回答