NULL OBJECT 模式

 

NULL OBJECT 模式

——《敏捷软件开发 原则、模式与实践(c#版)》第25章

    描述

    考虑如下代码

Employee e = DB.GetEmployee("Bob");
if(e!=null && e.IsTimeToPay(today))
{
   e.Pay();
}

 

    我们要从数据库中获取名为“Bob”的Employee对象。如果该对象不存在,DB对象就返回null;否则,就返回请求的Employee实例。如果雇员存在,并且到了他的发薪日,就调用Pay方法。

    我们以前都曾经编写过类似这样的代码。代码采用的惯用法很常见,因为在基于C的语言中,&&的第一个表达式会先求值,而仅当第一个表达式为true时才会对第二个表达式求值。大多数人也曾经由于忘记对null进行检查而受挫。该惯用法虽然很常见,但却是丑陋且易出错的。

    通过让DB.GetEmployee抛出一个异常而不是返回null,可以减少出错的可能。不过,try/catch块比对null的检查更加丑陋。

    可以使用NULL OBJECT 模式来解决这些问题。通常,该模式会消除对null进行检查的需要,并且有助于简化代码。

    实现

    在(图1-1)中展示了该模式的结构。Employee变成了一个具有两个实现的接口。EmployeeImplementation是正常的实现。它包含了Employee对象被期望拥有的所有方法和变量。当DB.GetEmployee在数据库中找到了一个雇员时,就返回一个EmployeeImplementation实例。仅当DB.GetEmployee在数据库中没有找到雇员是才返回NullEmployee的实例的。

 

    图1-1 NULL OBJECT 模式

    NullEmployee实现了Employee的所有方法,方法中“什么也没做”。“什么也没做”的含义和具体的方法有关。例如:有人会期望IsTimeToPay方法实现为返回false,因为根本不会为NullEmployee支付薪水。

    使用这个模式,最初的代码可以改为类似这样:

Employee e = DB.GetEmployee("Bob");
if(e.IsTimeToPay(today))
{
   e.Pay();
}

 

    这种做法既不易于出错又不丑陋,并且具有很好的一致性。DB.GetEmployee总是会返回一个Employee的实例。不管是否找到雇员,都可以确保所返回的实例具有合适的行为。

    当然,在许多情况下仍难想要知道是否DB.GetEmployee没有找到雇员。在Employee中创建一个持有唯一NullEmployee实例的static readonly变量,就可以达到这个目的了。

    DB.CS

// DB.cs
public class DB
{
   
public static Employee GetEmployee(string s)
   {
      
return Employee.NULL;
   }
}

 

    Employee.cs

Code

 

    使NullEmployee成为一个private内嵌类是一种确保该类只有单一实例的方法。其它任何人都无法创建NullEmployee的其它实例。这非常好,因为我们希望可以这样表达:

if(e==Employee.NULL)

   

    如果可以创建无效雇员类的多个实例,那么这种表达方式就是不可靠的。

 

    End.

 

posted @ 2009-06-04 14:53  Old  阅读(1476)  评论(1编辑  收藏  举报