Skip to main content
Engineering LibreTexts

10.6: Introduce Null Object

  • Page ID
    32426
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    Intent Eliminate conditional code that tests for null values by applying the Null Object design pattern.

    Problem

    How can you ease modification and extension of a class in presence of repeated tests for null values?

    This problem is difficult because:

    • Client methods are always testing that certain values are not null before actually invoking their methods.
    • Adding a new subclass to the client hierarchy requires testing null values before invoking some of the provider methods.

    Yet, solving this problem is feasible because:

    • The client does not need to know that the provider represents a null value.

    Solution

    Apply the Null Object pattern, i.e., encapsulate the null behavior as a separate provider class so that the client class does not have to perform a null test.

    Detection

    Look for idiomatic null tests.

    Null tests may take different forms, depending on the programming language and the kind of entity being tested. In Java, for example, a null object reference has the value null, whereas in C++ a null object pointer has the value 0.

    Transformation from a situation based on explicit test of null value to a situation where a Null Object is introduced.
    Figure \(\PageIndex{1}\): Transformation from a situation based on explicit test of null value to a situation where a Null Object is introduced.

    Steps

    Fowler discusses in detail the necessary refactoring steps [FBB+99].

    1. Identify the interface required for the null behavior. (This will normally be identical to that of the non-null object.)

    2. Create a new abstract superclass as a superclass of the RealObject class.

    3. Create a new subclass of the abstract superclass with a name starting with No or Null.

    4. Define default methods into the Null Object class.

    5. Initialize the instance variable or structure that was checked to now hold at least an instance of the Null Object class.

    6. Remove the conditional tests from the client.

    If you still want to be able to test for null values in a clean way, you may introduce a query method called isNull in RealObject and Null Object classes, as described by Fowler [FBB+99].

    Tradeoffs

    Pros

    • The client code is much simpler after applying the pattern.
    • The pattern is relatively simple to apply since the interface of the provider does not have to be modified.

    Cons

    • The provider hierarchy becomes more complex.

    Difficulties

    • Multiple clients may not agree on the reasonable default behavior of the Null Object. In this case, multiple Null Object classes may need to be defined.

    When the legacy solution is the solution

    • If clients do not agree on a common interface.

    • When very little code uses the variable directly or when the code that uses the variable is well-encapsulated in a single place.

    Example

    The following Smalltalk code is taken from Woolf [Woo98]. Initially the code contains explicit null tests:

    VisualPart>>objectWantedControl
        ...
        ↑ctrl isNil
            ifFalse:
                [ctrl isControlWanted
                    ifTrue:[self]
                    ifFalse:[nil]]
    

    It is then transformed into :

    VisualPart>>objectWantedControl
        ...
        ↑ctrl isControlWanted
            ifTrue:[self]
            ifFalse:[nil]
    Controller>>isControlWanted
        ↑self viewHasCursor
    NoController>>isControlWanted
        ↑false
    

    This page titled 10.6: Introduce Null Object is shared under a CC BY-SA license and was authored, remixed, and/or curated by Serge Demeyer, Stéphane Ducasse, Oscar Nierstrasz.

    • Was this article helpful?