美文网首页
Null Object模式

Null Object模式

作者: AlgoPeek | 来源:发表于2019-02-02 11:12 被阅读0次

    对很多面向对象语言,像C++、Java、C#等,对象可能为空,我们在调用对象的方法时,通常会先检查对象是否为null, 然后再调用,否则可能造成崩溃或空指针异常。看看下面的代码:

    Employee e = DB.getEmployee("Bob");
    if (e != null && e.isTimeToPay(today)) {
        e.pay();
    }
    

    我们可能曾经都编写过类似的代码,这是一个惯用法。当雇员Bob不存在时,会返回null值,&&的第一个表达式会被首先求值,当且仅当第一个表达式为true时才会执行第二个表达式。如果忘记对第一个表达式进行检查,可能就会出现各种bug。

    Null Object模式主要是消除对null进行检查,并简化代码。

    对于上面例子,如果把Employee变成一个抽象接口,EmployeeImpl实现期望的方法,而NullEmployee也实现接口的所有方法,但“什么也没做”,对isTimeToPay方法的实现直接返回false,类结构如下:

    使用Null Object模式,上面的代码可以改写成这样:

    Employee e = DB.getEmployee("Bob")
    if (e.isTimeToPay(today)) {
        e.pay();
    }
    

    即使是Bob不存在,也会返回一个NullEmployee的对象,该对象调用isTimeToPay时返回false,符合预期。

    但是在实际情况中,虽然Null Object实现的接口“什么也没做”,但Null Object的实现可能并不符合预期的,我们可能需要一个方法(类似empty、valid)来检查这个对象是否是我们期望的对象。看看pugixml的一个例子:

    pugi::xml_document doc;
    pugi::xml_parse_result result = doc.load_string("<node>hello pugixml</node>");
    if (result) {
        pugi::xml_node node = doc.child("node");
        if (!node.empty()) {
            std::cout << node.text().as_string() << std::endl;
        }
    
        node = doc.child("node_not_exists");
        std::cout << node.text().as_string("please check node exists!") << std::endl;
    }
    

    在上面的例子中,我们要获取xml中node结点的值,DOM解析成功后,通过pugi::xml_document的child方法返回node结点,通过empty()方法检查node结点的有效性,再获取node结点的值。

    当node结点不存在时返回的是什么呢?实际上就是一个空的xml_node结点(Null Object),我们可以对这个空结点调用所有xml_node的方法,只是这些方法“什么也没做”。像上面例子中,node_not_exists结点并不存在,返回了一个空的xml_node结点,如果我们直接获取其值,将得到一个空字符串,但我们可以指定一个默认值。

    像对C++这种支持操作符重载的语言,还可以直接利用语言特性,写出再简洁的代码,上面例子中获取结点值的逻辑可以修改如下:

    pugi::xml_node node = doc_child("node");
    if (node) {
        std::cout << node.text().as_string() << std::endl;
    }
    

    你可能要问,这跟判断对象是否为空有什么区别呢?

    在我看来,它们本质上是没什么区别的,但是null是语言层面上对空对象、空指针定义,而Null Object是业务层面对空对象的定义,它们本不是一个维度的东西,只是在实际应用中,我们经常将null作为业务层面的空对象使用。
    通过Null Object模式可以规避掉语言层面上对空引用时所引发的异常,并且可以让代码更加简洁和可读。虽然使用Null Object模式需要做一层额外的抽象,但它所来代码的简洁性和收益是值得的。

    参考:

    1. 敏捷软件开发,原则、模式与实践
    2. Null object pattern

    相关文章

      网友评论

          本文标题:Null Object模式

          本文链接:https://www.haomeiwen.com/subject/uefssqtx.html