一种选择是不必检查状态是否存在,方法是为所有联系人(在创建联系人时)提供不执行任何操作的默认状态。
您可以将其称为 Null Object 惯用语:在其他情况下使用 null(C、C++、Java)或 NULL (SQL) 的对象——这实际上是 Smalltalk 对 nil 所做的;nil 是一个特殊的对象,UndefinedObject 类的一个实例。
这个习惯用法的优点是您不必检查“对象不存在”条件,也不必对其进行特殊处理。这使得代码更简洁,也更面向对象,因为您的 Null Object 实例,而不是调用代码,可以确定调用其方法时要做什么。
这是一个使用责任链模式的 Java 示例。责任链基本上意味着拥有一个处理程序列表,每个处理程序都处理某些事情(一个命令)或将其传递给链中的下一个处理程序。我们将创建一个空对象处理程序,当它被要求处理某事时它什么也不做。
一、总承包:
interface Handler {
void handle( Command c ) ;
}
然后是 Null 处理程序,带有(恐怖!)单例:
class NullHandler implements Handler {
public static void NullHandler singleton = new NullHandler();
void handle( Command c ) { /*no-op*/}
}
然后是其他所有类型的 Handler 的基类(这也使用了模板方法模式,这只是一个实现细节):
abstract class BaseHandler implements Handler {
private Handler next;
public BaseHandler( Handler next ) {
this.next = next ;
}
public BaseHandler() {
this( NullHandler.singleton ) ;
}
public void handle( Command c ) {
if( canHandle( c ) {
doHandle( c ) ;
} else {
next.handle( c ) ;
}
}
//Template Method hooks
abstract boolean canHandle( Command c ) ;
abstract void doHandle( Command c ) ;
}
所以我们在这里得到的东西是有限的——我们可以做next.handle( c ) ;
而不是做if next != null next.handle( c ) ;
。但随着我们添加更多代码,价值变得更加明显。
假设我们要打印我们的责任链。一种方法是在我们的代码中外部化迭代链,每次测试以查看 next == null。
但更好,更面向对象,我们可以让链自己做。同样,在BaseHandler
's print 中,我们将打印该实例的名称,然后调用next
's print 方法。NullHandler 中的print
方法不会打印任何内容,或者可能会打印“链结束”。