6

最近我遇到了空对象设计模式,我的同事说它可以用来消除在整个代码中遇到的空指针检查。

例如,假设一个 DAO 类返回有关客户的信息(在一个名为 CustomerVO 的值对象中)。我的主类应该提取 firstName 和 emailId 并向客户发送电子邮件。

...
CustomerVO custVO = CustomerDAO.getCustomer(customerID);
if(custVO != null) { // imp, otherwise we may get null ptr exception in next line
     sendEmail(custVO.getFirstName(), custVO.getEmailID());
}
...

这是一个非常简单的例子,但是这种空检查可以根据值对象的复杂性迅速传播到整个代码中。

我有两个关于空值检查的问题 - 它们往往使代码变得丑陋且难以阅读 - 经验不足的开发人员在实际上应该抛出异常时进行了不必要的空值检查。例如,在上面的代码中,最好从 getCustomer() 本身抛出异常,因为如果它无法找到给定 CustID 的客户信息,则表明 CustID 无效。

好的,回到空对象模式,我们可以使用“空”CustomerVO 对象来隐藏空检查吗?

CustomerVO {
   String firstName = "";
   String emailID = ""; 
}

不要这样有意义。你怎么看?

以及在您的应用程序中最小化空检查的操作是什么。

4

5 回答 5

3

虽然空对象模式有它的用途,但您仍然需要在此处进行检查,否则您将尝试sendEmail()使用空字符串的电子邮件地址(或者您将检查推送到sendEmail(),这可能就像轻松检查null)。

如果CustomerVO类实现了该sendEmail()方法,那么空对象模式在这里真正有用的地方。那么您可以简单地将调用链接在一起,因为合约getCustomer()将确保null不会返回引用:

CustomerDAO.getCustomer(customerID).sendEmail();

在这种情况下,该sendEmail()方法将检查它是否被要求对特殊的“空对象”采取行动,并且什么也不做(或任何适当的事情)。

于 2010-10-17T06:09:22.033 回答
2

在这种情况下,空对象可能不合适,因为默认值实际上可能隐藏了实际上是异常的内容。如果您发现自己必须检查您是否有安全的 null 来执行其他活动,那么 null 模式不会给您带来任何好处。

正如您所说,许多新开发人员花时间试图保护他们的代码免受比停止程序更糟糕的异常情况。

于 2010-10-17T06:07:18.177 回答
1

getCustomer如果找不到客户,您的方法是否应该抛出异常,而不是返回 null?

答案当然是视情况而定:几乎永远不会出现客户 ID 不存在的情况?换句话说,这是一个例外情况吗?如果是这样,则例外是适当的。

但是,在数据访问层中,某些东西不存在通常是很正常的。在这种情况下,最好不要扔,因为这不是意外的例外情况。

“返回具有空字段的非空对象”可能不会更好。如果不添加一些可能比空检查更糟糕的检查代码,您如何知道返回的对象是否“有效”?

因此,如果获取的内容不存在可能是正常状态,则空值检查模式可能是最好的。如果这是意外情况,那么让数据访问方法抛出 NotFound 异常可能会更好。

于 2010-10-17T06:19:05.487 回答
1

我对这种类型的代码有疑问,这是一种常见的模式。如果你分解你实际在做的事情,你根本不需要空检查。在我看来,这里的问题是你违反了 SRP。

该方法CustomerVO custVO = CustomerDAO.getCustomer(customerID);做了两件事。

首先,如果客户存在,则返回一个客户;其次,如果没有这样的客户,则返回 null。这是两个不同的操作,应该这样编码。

更好的方法是:

bool customerExists = CustomerDAO.exists(customerID);

if (customerExists)
{
  CustomerVO custVO = CustomerDAO.getCustomer(customerID);
  sendEmail(custVO.getFirstName(), custVO.getEmailID());
}
else
{
   // Do whatever is appropriate if there is no such customer.
}

}

因此,将方法一分为二,一是检查请求的对象是否存在,二是实际检索它。不需要任何异常,设计和语义非常清晰(在我看来,它不是不存在返回空模式)。此外,在这种方法中,如果请求的客户不存在,该CustomerDAO.getCustomer(customerID)方法会抛出。ArgumentException毕竟,你已经要求了一个Customer,但没有一个。

此外,在我看来,任何方法都不应该返回nullNull明确地说,'我不知道正确答案是什么,我没有返回的价值'。 Null不是意义,是缺乏意义。问问自己,‘为什么我要退回一些我知道不应该真的发生的事情?你的方法GetCustomer应该返回一个Customer明显的。如果你 return null,你只是在推回调用链并破坏合同的责任。如果有有意义的默认值,请使用它,但在这里抛出异常可能会让您更难思考正确的设计是什么。

于 2012-05-15T15:53:44.443 回答
0

该名称是 NULL 对象设计模式,而不是 NULL 检查设计模式。空对象表示没有对象。当您有对象在 COLLLABORATION 中工作时,应该使用它。在您的情况下,您正在检查 NULL 检查应该没问题的对象的存在。

NULL 设计模式并不意味着取代 NULL 异常处理。这是 NULL 设计模式的附带好处之一,但其目的是提供默认行为。

不应将 NULL 检查替换为 NULL 设计模式对象,因为它可能导致应用程序中的静默缺陷。

请参阅下面的文章,其中详细介绍了 NULL 设计模式的 DO 和 Donts。

http://www.codeproject.com/Articles/1042674/NULL-Object-Design-Pattern

于 2015-10-30T07:50:45.410 回答