Null Object Something for Nothing

In his paper written in 2003, Kevlin Henney presents the NullObject Pattern to deal with objects that potentially can be null and that should, if they are null, behave in a default manner this without requiring an explicit null check.

Below I give a quick summary of the idea for details you should check his paper.

A prototypic example is a logging class that is used for example in a service.  You want this to work even if no logging was configured without having to write things like:

If (log!=null) 
  log.write(?ervice Started?;

As programmer all the not-null checks clutter your code. It has nothing to do with business logic and moreover it is very error prone.  For every log write you must not forget to add the conditional check. Whereas in the business part of your code you want to treat nulls as exceptions, in this case a null is not an unexpected value. To repeat the words of Fowler and Hunt: ‘Duplicate code is considered to have a bad smell’. Don’t Repeat Yourself principle (DRY)

The solution, according to Henney, is to introduce something for nothing: the NullObject pattern. This is a common pattern found in other situations as well: null iterator, null command, …

The NullLog will be implemented as follows:

public interface Log
{
  void write(String messageToLog);
}

public class NullLog implements Log
{
  public void write(String messageToLog)
  {
  }
}

Now, instead of, having an optional relationship between a log and the service we must enforce it to have mandatory relationship. If no explicit logger is used the service will use the NullLog. We can enforce this, for example, in the constructor of the service that uses the logger.

public class Service
{
  public Service()
  {
    this(new NullLog());
  }

  public Service(Log log)
  {
    this.log = log;
    ...
  }

  private Log log;
}

In the remainder of his paper, Henney points out potential problems to this approach. How to deal with return values, out and/or in-out parameters in methods of the NullObject? The solution can be summarized in choosing intelligent defaults. For example if an int must be returned by a NullObject, we could return 0. In fact two major approaches are possible:

  • use a meaningful defaults or success defaults: 0 for an int
  • use default that result in errors or failure defaults: NaN or infinity for floating points

Since a NullObject is stateless all instances of the object are equal. So a reference to single static instance should be returned when the NullObject is instantiated.

image_pdf

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.