2009-05-19 70 views
3

假设您有一个可以完成某种工作的子系统。它可能是任何东西。显然,在这个子系统的入口点上,输入会有一定的限制。假设这个子系统主要由GUI来调用。子系统需要检查它收到的所有输入以确保它是有效的。如果输入无效,我们不想FireTheMissles()。 UI也对验证感兴趣,因为它需要报告出错的地方。也许用户忘了指定一个目标或者在启动板本身瞄准导弹。当然,你可以返回一个空值或者抛出一个异常,但是这并不能告诉用户什么地方出错了(当然,除非你为每个错误编写一个单独的异常类,如果if这是最佳做法)。在输入验证中避免重复的代码

当然,即使有例外,你也有问题。用户可能想知道输入是否有效,然后单击“Fire Missles!”按钮。你可以编写一个单独的验证函数(当然IsValid()并没有真正的帮助很多,因为它不会告诉你什么出了问题),但是你会从按钮点击处理函数中调用它,然后再从FireTheMissles中调用它( )函数(我真的不知道这是如何从一个模糊的子系统变成一个引火计划)。当然,这并不是世界的尽头,但似乎很愚蠢的是连续调用两次相同的验证函数而没有任何改变,特别是如果这个验证函数需要计算1GB文件的散列值。

如果函数的前提条件是清晰的,GUI可以进行自己的输入验证,但是我们只是复制了输入验证逻辑,而其中的更改可能不会反映在另一个中。当然,我们可以在GUI上添加一张支票以确保导弹目标不在盟国内,但如果我们忘记将它复制到FireTheMissles()例程中,那么当我们切换到时会意外炸毁我们的盟友一个控制台界面。

因此,简而言之,你如何实现以下目标:

  1. 输入验证,告诉你不只是出事了,但具体是什么地方出了错。
  2. 能够在不调用依赖它的函数的情况下运行此输入验证。
  3. 没有双重验证。
  4. 没有重复的代码。

另外,我只是想到了这一点,但错误消息不应该写在FireTheMissles()方法中。 GUI负责选择适当的错误消息,而不是GUI调用的代码。

回答

3

“的子系统需要检查所有收到以确保它是有效的投入”的投入没有那么多的参数列表

想,但作为一个消息,它会之后更容易。

消息类有一个IsValid成员函数,它会记住IsValid是否被调用以及结果是什么。它还会记住它的状态,如果状态发生变化,那么它需要重新验证。这个消息类还保留了一个验证错误列表。

现在,UI会生成一个TargetMissiles消息,UI可以验证它,或直接将其传递给MissileFiring子系统,它会检查消息是否已验证,如果验证不成功,则继续/失败,取决于。 用户界面获取消息,验证列表已填充。

带有验证的消息位于单独的库中。没有代码是重复的。

This sound OK?

2

这就是Model-View-Controller的全部内容。

您建立了一个模型(由坐标,导弹类型和导弹数组成的发射),并且该模型具有一个返回错误/警告列表的验证方法。当您更新模型时(在键入时,按下按钮),您调用验证方法并向用户显示任何警告,错误等。(Eclipse在对话框中的工具栏下方有一个小区域这样做,你可能想看看。)

当模型是有效的,你激活发射导弹按钮,以便用户知道他们可以发射导弹。如果您有特别频繁地调用的更新事件或特别昂贵的验证的一部分,那么您可以在模型上使用validate_light方法来验证仅容易执行的部分。

当您切换到基于控制台的UI时,可以从命令行参数构建模型,调用相同的验证方法(并将错误报告给stderr),然后启动导弹。

+0

MVC比输入验证要多得多。当它到达输入验证本身时,你所建议的与Binary Worrier提出的有什么不同?如果是这样,怎么样?如果没有,那么为了实现这种错误处理方法,是否真的有必要做MVC? (并不是说最终的应用程序肯定不会是MVC,但我甚至没有考虑过GUI,除非知道它将需要从我的导弹发射子系统中得到什么。) – 2009-05-19 13:07:43

+0

+1简而言之:模型定义它的任何部分是有效的,任何人都必须确保他们听从这些限制。 – 2009-05-19 14:20:22

0

我会建议一个输入验证类,它在其构造函数中接受输入类型(一个枚举),并提供一个公有的IsValid方法。

IsValid方法应该返回一个布尔值TRUE为有效,而为无效返回FALSE。它还应该有一个OUT参数,它接受一个字符串并将状态消息分配给该字符串。调用者可以自由地忽略该消息,如果它适合上下文,或者将其报告给GUI。

因此,在伪代码(原谅德尔福的语法,但它应该是可读的任何人):

//different types of data we might want to validate 
TValidationType = (vtMissileLaunchCodes, vtFirstName, 
    vtLastName, vtSSN); 

TInputValidator = class 
public 
    //call the constructor with the validation type 
    constructor Create(ValidationType: TValidationType); 

    //this should probably be ABSTRACT, implemented by descendants 
    //if you took that approach, then you'd have 1 descendant class 
    //for each validation type, instead of an enumeration 
    function IsValid(InputData: string; var msg: string): boolean; 

然后使用它,你会做这样的事情:

procedure ValidateForm; 
var 
    validator: TInputValidator; 
begin 
    validator := TInputValidator.Create(vtSSN); 
    if validator.IsValid(edtSSN.Text,labelErrorMsg.Text) then 
    SaveData; //it's valid, so save it! 
    //if it wasn't valid, then the error msg is in the GUI in "labelErrorMsg". 
end; 
0

每条数据都有自己的元数据(类型,格式,单位,掩码,范围等)。不幸的是,这并不总是指定。

GUI控件需要检查包含元数据的输入,并在数据无效时发出警告/错误。

例如:一个数字有一个范围。范围由元数据提供,但范围检查由控件提供。

1

双验证。在许多情况下,验证是三重的(例如,DB中的FK和非空字段)。根据您的平台,可能会对验证规则进行一次编码。例如,您的前端和后端代码可以共享C#业务类。或者,您可以将验证规则存储为后端和前端都可以访问应用程序的元数据。

事实上,你需要不同的响应来验证问题(例如火灾导弹按钮甚至不应该启用,直到其他输入有效),将会有不同的代码与相同的规则相关联。