最近我遇到了Null Object设计模式,我的同事说它可以用来取消整个代码中遇到的空指针检查。
例如,假设DAO类返回有关Customer的信息(在名为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());
}
...
这是一个非常简单的示例,但是这样的空检查可以根据值对象的复杂性快速传播到整个代码中。
我有两个null检查问题, - 他们倾向于使代码丑陋且难以阅读 - 经验较少的开发人员进行不必要的空检查,实际上他们应该抛出异常。例如在上面的代码中,最好从getCustomer()本身抛出异常,因为如果它无法找到给定CustID的客户信息,则表明CustID无效。
好的,回到null对象模式,我们可以使用'null'CustomerVO对象隐藏空检查吗?
CustomerVO {
String firstName = "";
String emailID = "";
}
不要有意义。你觉得怎么样?
为了最大限度地减少应用中的空值检查,您遵循了哪些内容?
答案 0 :(得分:3)
虽然空对象模式已经使用了,但您仍然需要在这里进行检查,否则您将尝试sendEmail()
到一个空字符串的电子邮件地址(或者您推送检查sendEmail()
,这可以轻松检查null
)。
如果CustomerVO
类实现了sendEmail()
方法,那么空对象模式在这里真的很有用。然后你可以简单地将调用链接在一起,因为getCustomer()
的契约将确保不会返回null
引用:
CustomerDAO.getCustomer(customerID).sendEmail();
在这种情况下,sendEmail()
方法会检查它是否被要求对特殊的“空对象”采取行动,而不做任何事情(或任何适当的事情)。
答案 1 :(得分:2)
在这种情况下,null对象可能是不合适的,因为默认值可能实际上隐藏了实际的异常。如果您发现自己必须检查是否有安全null来执行其他活动,则null模式不会为您购买任何东西。
正如您所说,许多新开发人员花时间尝试保护他们的代码免受异常情况的影响,而这种情况比停止程序更糟糕。
答案 2 :(得分:1)
如果找不到客户,您的getCustomer
方法是否会抛出异常,而不是返回null?
答案当然是,它取决于:几乎从不是否存在客户ID?换句话说,这是一个特例吗?如果是这样,则例外是恰当的。
但是,在数据访问层中,某些东西不存在通常是很正常的。在这种情况下,最好不要抛出,因为它不是一个意想不到的特殊情况。
'返回一个具有空字段的非null对象'可能没有任何好处。如果没有添加一些可能比空检查更差的检查代码,你怎么知道返回的对象是否“有效”?
因此,如果不存在被提取的内容可能是正常状态,则空检查模式可能是最佳的。如果它是意外的,那么让数据访问方法抛出NotFound异常可能会更好。
答案 3 :(得分: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.
}
}
因此,将方法拆分为两个,一个检查请求的对象是否存在,另一个检查实际检索它。不需要任何异常,并且设计和语义非常清楚(在我看来,它不是一个不存在的返回null模式)。此外,在此方法中,如果请求的客户不存在,CustomerDAO.getCustomer(customerID)
方法将抛出ArgumentException
。毕竟,你已经要求Customer
并且没有一个。
此外,在我看来,没有方法应该返回null
。 Null
明确地说,'我不知道正确的答案是什么,我没有回报的价值'。 Null
不是意义,它是缺乏的含义。问问自己,“为什么我要归还一些我知道不应该发生的事情?您的方法GetCustomer
应该明显返回Customer
。如果您返回null
,那么您只是负责支持如何备份调用链并违反合同。如果有有意义的默认值,请使用它,但在此处抛出异常可能会让您对正确的设计更加困难。
答案 4 :(得分:0)
名称是NULL对象设计模式而不是NULL检查设计模式。空对象表示没有对象。当您在COLLABORATION中使用对象时,应该使用此方法。在您的情况下,您正在检查是否存在对其进行NULL检查的对象。
NULL设计模式并不意味着替换NULL异常处理。这是NULL设计模式的附带好处之一,但目的是提供默认行为。
不应将NULL检查替换为NULL设计模式对象,因为它可能导致应用程序中出现静默缺陷。
请参阅下面的文章,其中详细介绍了DO设计模式的DO和Donts。
http://www.codeproject.com/Articles/1042674/NULL-Object-Design-Pattern