哪个合同(按合同设计)更好?

时间:2009-01-05 19:48:03

标签: exception exception-handling error-handling

假设我有一个方法

public Patient(int id)
{
    ----
}

返回给定id的Patient对象..我可以用2种方式定义合约

  1. 如果患者不存在,方法将返回null
  2. 如果患者不存在,方法将抛出异常。在这种情况下,我还将定义一个查询方法,如果患者存在于数据库中则返回true,否则返回false ...
  3. 我应该使用哪种合约?还有其他建议吗?

    更新:请对这个案子发表评论...... 如果它不是一个分配了Id的数据库,那就是用户在UI中输入的东西......比如SSN ..那么哪一个更好..

    评论史蒂夫的Null模式,我认为是有效的: 这里可能不是一个好主意,因为当ID不存在时立即知道它真的很有用。

    而且我也认为这里的Null模式会有点重量

    Rob Wells关于抛出异常的评论,因为它的错误ID: 我不认为患者姓名中的拼写错误是一种特殊情况“恕我直言”

9 个答案:

答案 0 :(得分:15)

请记住,“通过线路”到另一层(无论是数据库还是应用程序服务器)是您可以执行的最昂贵的活动之一 - 通常网络呼叫将比以下任何时候都要长几个数量级。记忆电话。

因此,在构建API时避免冗余调用是值得的。

考虑一下,如果您的API是这样的:

// Check to see if a given patient exists
public bool PatientExists(int id);

// Load the specified patient; throws exception if not found
public Patient GetPatient(int id);

然后你可能会两次点击数据库 - 或者依赖于良好的缓存来避免这种情况。

另一个考虑因素是:在某些地方,您的代码可能具有“已知良好”ID,而在其他地方则不然。每个位置都需要一个不同的策略来判断是否应该抛出异常。

这是我过去常用的一种模式 - 有两种方法:

// Load the specified patient; throws exception if not found
public Patient GetExistingPatient(int id);

// Search for the specified patient; returns null if not found
public Patient FindPatient(int id);

显然,可以通过调用FindPatient()来构建GetExistingPatient()。

这允许您的调用代码获取适当的行为,如果出现错误则抛出异常,并避免在不需要的情况下处理异常。

答案 1 :(得分:4)

另一种选择是Null Object pattern

答案 2 :(得分:4)

你应该抛出异常。如果您的id没有指向有效的患者,那么它来自哪里?可能发生了非常糟糕的事情。这是一个特例。

编辑:如果您正在执行基于整数的检索以外的操作,例如基于文本的搜索,则返回null就可以了。特别是因为在这种情况下,您将返回一组结果,这些结果可能不止一个(多个患者姓名相同,出生日期相同,或者您的标准是什么)。

搜索功能应与检索功能具有不同的合约。

答案 3 :(得分:2)

对于这种情况,我会让方法为不存在的患者返回null。

当系统本身出现问题时,我更倾向于使用异常来帮助降低graeful降级。

在这种情况下,很可能是:

  1. 患者身份证中的拼写错误(如果已输入搜索表单),
  2. 数据输入错误,或
  3. 工作流程问题,即患者的记录尚未输入。
  4. 因此,返回null而不是异常。

    如果联系数据库时出现问题,那么我会让该方法引发异常。

    编辑:刚看到签名中的患者ID是一个整数,感谢Steven Lowe,所以我已经更正了我的原因列表。

    关于描述何时使用异常(对于系统错误)与其他返回错误的方法(对于简单的数据输入拼写错误)的基本观点仍然存在。 IMHO。

    HTH

    欢呼声,

    罗布

答案 4 :(得分:2)

取决于:

如果您认为正常操作会导致数据库编号与数据库中的文件不匹配,则应返回空(NULL)记录。

但是如果你期望给定的ID应该总是打到一个记录,那么当找不到一个(这应该是罕见的)然后使用异常。

DB连接错误等其他问题应该会产生异常 正如您在正常情况下所期望的那样,对DB的查询始终有效(尽管它可能返回0条记录)。

P.S。我不会返回指针。 (谁拥有指针?)
我会返回一个可能有或没有记录的对象。但是你可以在内部记录存在的内存。可能是智能指针或比理解cotext的智能指针更聪明的东西。

答案 5 :(得分:1)

在这样的简单情况下1.似乎绰绰有余。您可能希望实现类似于客户端调用的回调方法,以了解它返回null的原因。只是一个建议。

答案 6 :(得分:1)

将你的descriptiong用于面值,你可能需要两者:

  • 错误的ID是错误/例外,正如亚当指出的那样,但是
  • 如果您在其他地方获得可能已经消失的ID,则需要使用查询方法来检查它们

答案 7 :(得分:0)

假设我正确阅读了...... 当您致电Patient(100)时,它将返回ID为100的患者的对象参考。 如果不存在id为100的患者,我认为它应该返回null。例外是过度使用IMO,这种情况并不需要它。该函数只返回null。它没有创建一些可能导致应用程序崩溃的错误情况(当然,除非您最终没有处理该null并将其传递给应用程序的其他部分)。

我肯定会让该函数返回'null',特别是如果它是某些搜索的一部分,用户将搜索具有特定ID的患者,并且如果对象引用最终为null,则它只会声明没有患有这种身份的患者。

答案 8 :(得分:0)

抛出异常。

如果返回null,则代码如下:

Console.WriteLine(Patient(id).Name);
如果id不存在,

将失败并返回NullReferenceException,这不如说PatientNotFoundException(id)有用。在这个例子中,它仍然相对容易追踪,但考虑:

somePatient = Patient(id)

// much later, in a different function:

Console.WriteLine(somePatient);

关于添加检查患者是否存在的功能:请注意,这不会完全阻止PatientNotFoundExceptions。例如:

if (PatientExists(id))
    Console.WriteLine(Patient(id).Name);

- 另一个线程或其他进程可以在对PatientExists和Patient的呼叫之间删除患者。此外,这将意味着两个数据库查询而不是一个。通常,最好只是尝试调用,并处理异常。

请注意,返回多个值的查询的情况不同,例如作为清单;在这里,如果没有匹配则返回空列表是合适的。