设计模式 学习笔记 之九

第12章 Null Object模式

在C++和Java编程中,我们经常要判断一个对象引用是否为NULL/null。只有在它不为NULL/null的前提下,我们才对它时行相应的操作。下面是分别使用Java和C++来写出的同一段逻辑。

C++

Employee* e = DBFacade::getEmployee("Bob");

if (e != NULL && e->isTimeToPay(today))

{

    e->pay();

}

Java

Employee e = DBFacade.getEmployee("Bob");

if (e != null && e.isTimeToPay(today))

{

    e.pay();

}

这种对NULL/null的判断充斥在我们的代码中,看上去总是有点丑陋。更严重的问题是,有时我们会忘记检查NULL/null,从而带来程序崩溃的后果。而最严重的问题是,如果我们忘记检查NULL/null,程序并不会每次都崩溃,可能在软件开发过程中,程序都能正常运行,但是,当它真正部署到用户环境中时,却发生了崩溃!

我们可以使用Null Object模式来解决这个问题。通常这个模式会消除对NULL/null进行检查的需要,并且有助于简化代码。下图显示了这个设计。

clip_image002

NullEmployee类应该覆盖Employee类的所有public方法,并在这些方法中“do nothing”。这里的“do nothing”取决于Employee类的方法做了些什么。比如,isTimeToPay()方法对于NullEmployee来说就应该总是返回false,因为绝不会存在为NullEmployee支付薪水的那一天。

Null Object模式也是一个比较简单的模式,因此这里我们也重点关注它的实现。我们一般是让NullEmployee成为Employee的内部类,同时让NullEmployee的单例成为Employee类的一个常值字段NULL或一个静态方法。下表给出了Java和C++的代码。

C++

class Employee

{

public:

    virtual bool isTimeToPay(int today)

    {

        ... do something here ...

    }

   

    virtual void pay()

    {

        ... do something here ...

    }

 

    static Employee* null()

    {

        class NullEmployee : public Employee

        {

        public:

            bool isTimeToPay(int today)

            {

                return false;

            }

 

            void pay() {}

        };

 

        static NullEmployee null;

        return (&null);

    }

};

Java

public class Employee

{

    public boolean isTimeToPay(Date today)

    {

        ... do something here ...

    }

    public void pay() {

        ... do something here ...

    }

 

    public static final Employee NULL = new NullEmployee();

    private static class NullEmployee extends Employee

    {

         @Override

         public boolean isTimeToPay (Date today)

        {

            return false;

        }

        @Override

        public void pay() {}

    }

}

有了Null Object,原先的代码可以写成

C++

Employee* e = DBFacade::getEmployee("Bob");

if (e->isTimeToPay(today))

{

    e->pay();

}

Java

Employee e = DBFacade.getEmployee("Bob");

if (e.isTimeToPay(today))

{

    e.pay();

}

我们也可以把一个Employee对象引用与Null Object进行比较,就像下面的代码所示:

C++

if (e == Employee::null())

{

     do something here

}

Java

if (e == Employee.NULL)

{

    do something here

}

但是,由于使用Null Object模式的初衷就是为了让我们不必去把一个对象引用同NULL/null比较,因此上面的这段代码基本是不需要的。

小结

Null Object模式是一种简单但实用的模式,通过它可以消除对NULL/null的检查,这样做既简化了代码,也避免了因为忘记检查NULL/null而引发的程序异常崩溃的情况。但是使用Null Object模式也要求建立编码规范,即所有原先返回NULL/null的地方,都要用Null Object来代替。

posted @ 2011-05-10 11:11  李嘉 (Justin)  阅读(222)  评论(0编辑  收藏  举报