9

假设我有一个看起来像这样的函数:

public void saveBooking(/* some inputs */) {
    //save into database
}

在保存到数据库之前,我必须进行各种验证。我在我的主程序中可以做的是这样的:

//do all the validations and do any necessary handling. Then...
saveBooking(/*inputs*/);

有了这个,我确信所有数据在保存到数据库之前都必须通过所有所需的验证。但是,这意味着该功能saveBooking()密切依赖于验证方法。每次我想打电话saveBooking()时,我都必须确保我不会忘记调用验证。

或者,我可以将所有验证放在函数本身中,这样我所要做的就是调用该方法,一切都会得到处理。但是,为了独立处理所有错误,我必须让函数抛出异常并在主程序中捕获。它应该看起来像这样:

public void saveBooking(/* some inputs */) /* throws various exceptions */ {
    //various validations
    //save into database
}

//...and in the main program...
try{
    saveBooking(/*inputs*/);
}
catch(MyException1 e1){
    //do something
}
catch(MyException2 e2){
    //do something
}

这也意味着我必须自己创建多个异常。好消息是我不必担心我必须事先进行哪些验证。

有了这些,我不确定哪一个是最好的代码设计。我个人更喜欢第一种方法,它更具可读性,但它相互依赖太多,当我需要在很多地方使用它时,情况会变得更糟。请指教!

4

5 回答 5

8

绝对是第二个选项的第一个选项。我认为第二种是滥用例外。例外是针对特殊情况的,验证失败并不是“例外”。

每次我想打电话saveBooking()时,我都必须确保我不会忘记调用验证。

将验证逻辑放入一个单独的方法中,并saveBooking()在它执行任何其他操作之前调用验证方法。

public List<ValidationError> validateBooking(/* args */)
{
    // as @Jared Farrish suggests, return a list of validation errors
}

public boolean saveBooking(/* args */)
{
    List<ValidationError> errors = validateBooking(/* args */);

    if (errors.size() != 0) return false; // validation failed

    // save to the database

    return true;
}
于 2011-08-02T03:46:43.117 回答
2

检查通常应该在函数本身内进行,这样就不可能在没有首先验证数据的情况下尝试保存数据。如果没有函数中的这些检查,您可能会发现客户端试图在没有验证的情况下进行保存,这很少是一件好事。

但是您不限于为此使用异常,您可以简单地返回某种错误代码以供调用者检查。虽然我通常不关心错误是由异常还是返回码造成的,但有些人可能会认为这是对异常的滥用。

验证代码可能仍然作为一个单独的函数保留,因为您自己的代码可能希望在不进行保存的情况下调用它。类似(伪代码):

def validateStuff():
    if stuff is not valid:
        return WTF
    return OK

def saveBookings():
    rc = validateStuff()
    if rc != OK:
        return rc;
    save the information
    return OK

您仍然可能会通过调用saveBookingsif 来捕获异常,以处理 I/O 错误等,但这并不是绝对必要的:您也可以在函数中捕获这些异常并将它们转换为返回码。

try/catch 我倾向于喜欢每个函数的一种报告方法,因此我(例如)不必检查返回码。

于 2011-08-02T03:52:39.803 回答
1

通过在插入之前验证所有内容,您肯定是在做正确的事情,您还应该验证您插入的所有内容是否适合或满足数据库中的约束以避免意外的 SQLException,这是您不会预料到的,并且会全部通往顶峰的路。

我建议创建一个带有一些属性的自定义异常来描述错误的原因,这样你只需要担心捕获一种异常。

此外,我肯定会把验证放在方法中,所以它总是被调用。

于 2011-08-02T03:48:24.977 回答
0

将大量代码放在一个地方并不是一个好主意。抛出已检查的异常也不是一个好主意。

于 2011-08-02T04:02:57.860 回答
0

3 层方法相当常见,其中您有以下 3 层:

  • 客户端界面。这可以包括 Web 应用程序的 JavaScript 验证或 GUI 控件上的一些基本 SWT 验证。
  • 业务层。这一层知道业务规则。这是您通常想要放置服务器端验证的地方。任何应该保存、更改等的事情都应该通过业务层完成(这样你总是有你的验证并且你不关心你的数据存储)。
  • 数据层。该层通常是“哑”的。只需保存、删除、选择等;无论业务层要求什么,这一层都可以做到。

这非常简化,但它为您提供了一种体面的方法来分离不同类型的逻辑以便于维护。

于 2011-08-02T03:46:55.950 回答