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的实例的。

 

NULL OBJECT 模式_第1张图片

    图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

ContractedBlock.gif ExpandedBlockStart.gif Code
// Employee.cs
using System;

public abstract class Employee
ExpandedBlockStart.gifContractedBlock.gif
{
   
public abstract bool IsTimeToPay(DateTime time);
   
public abstract void Pay();
   
   
public static readonly Employee NULL=
     
new NullEmployee();
   
   
private class NullEmployee : Employee
ExpandedSubBlockStart.gifContractedSubBlock.gif   
{
      
public override bool IsTimeToPay(DateTime time)
ExpandedSubBlockStart.gifContractedSubBlock.gif      
{
         
return false;
      }

      
ExpandedSubBlockStart.gifContractedSubBlock.gif      
public override void Pay() {}
   }

}

 

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

if (e == Employee.NULL)

   

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

 

    End.

 

转载于:https://www.cnblogs.com/bruceleeliya/archive/2009/06/04/NullObject.html

你可能感兴趣的:(NULL OBJECT 模式)