8

假设我有一个方法

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

返回给定 id 的 Patient 对象。我可以通过 2 种方式定义合同

  1. 如果患者不存在,方法将返回 null
  2. 如果患者不存在,方法将抛出异常。在这种情况下,我还将定义一个查询方法,如果患者存在于数据库中则返回 true,否则返回 false...

我应该使用哪个合约?还有其他建议吗?

更新:请也对此案例发表评论...如果它不是数据库分配的 Id 并且它是用户在 UI 中输入的内容 .. 像 SSN .. 那么哪个更好..

我认为来自 Steve 的关于 Null 模式的评论是有效的:这里可能不是一个好主意,因为当 ID 不存在时立即知道会非常有用。

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

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

4

9 回答 9

14

请记住,“通过网络”到另一层(无论是数据库还是应用程序服务器)是您可以做的最昂贵的活动之一 - 通常网络调用将比内存调用长几个数量级。

因此,构建 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);

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

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

于 2009-01-05T20:03:22.757 回答
4

另一种选择是空对象模式

于 2009-01-05T19:52:41.530 回答
4

你可能应该抛出一个异常。如果您有一个id不指向有效患者的数据,它是从哪里来的?很可能发生了非常糟糕的事情。这是一种特殊情况。

编辑:如果你做的不是基于整数的检索,比如基于文本的搜索,那么返回null就可以了。特别是因为在这种情况下,您要返回一组结果,这些结果可能不止一个(不止一个具有相同姓名、相同出生日期或任何您的标准的患者)。

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

于 2009-01-05T19:53:09.143 回答
2

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

当系统本身出现问题时,我倾向于使用异常来协助严重降级。

在这种情况下,它可能是 mosdt:

  1. 如果在搜索表单中输入了患者 ID,则会出现拼写错误,
  2. 数据输入错误,或
  3. 尚未输入患者记录的工作流程问题。

因此,返回 null 而不是异常。

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

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

我关于描述何时使用异常(针对系统错误)与其他返回错误的方法(针对简单的数据输入错误)的基本观点仍然有效。恕我直言。

高温高压

干杯,

于 2009-01-05T19:55:36.313 回答
2

这取决于:

如果您认为正常操作会导致一个 pation number 与 DB 中的文件不匹配,则应返回一个空 (NULL) 记录。

但是,如果您希望给定的 ID 应该总是命中记录,那么当找不到记录时(这应该很少见),然后使用异常。

其他诸如数据库连接错误之类的事情应该会产生异常。
正如您在正常情况下所期望的那样,对数据库的查询始终有效(尽管它可能返回 0 条记录或不返回)。

PS我不会返回一个指针。(谁拥有指针??)
我会返回一个可能有也可能没有记录的对象。但是您可以询问其中记录的存在。可能是智能指针或比理解上下文的智能指针更智能的东西。

于 2009-01-05T20:03:20.747 回答
1

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

于 2009-01-05T19:54:10.640 回答
1

从表面上看你的描述,你可能需要两者:

  • 正如亚当指出的那样,错误的 ID 是错误/异常,但是
  • 如果您在其他地方获得了可能已经消失的 ID,您将需要查询方法来检查它们
于 2009-01-05T19:56:08.653 回答
0

假设我没看错……当您调用 Patient(100) 时,它将返回一个 id 为 100 的 Patient 的对象引用。如果不存在 id 为 100 的患者,我认为它应该返回 null。异常被过度使用 IMO,这种情况不需要它。该函数只是返回了一个空值。它没有创建一些可能导致您的应用程序崩溃的错误案例(当然,除非您最终没有处理该 null 并将其传递给应用程序的其他部分)。

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

于 2009-01-05T20:00:24.183 回答
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 之间删除患者。此外,这将意味着两个数据库查询而不是一个。通常,最好只尝试调用并处理异常。

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

于 2009-01-05T20:07:16.167 回答