Skip to content

Design Patterns: Null Object

Published: at 03:34 PM

Purpose

The Null Object design pattern allows you to eliminate the need for null checks, thereby reducing cyclomatic complexity and enhancing code safety.

The Problem

Consider the following code:

public class ItemView
{
    public ItemView(Item item)
    {
        if (item == null) throw new ArgumentNullException();

        // Perform some operations
    }
}

It’s common to see null checks like this when working with nullable arguments. However, these checks come at a cost: they increase the cyclomatic complexity of your code.

What is Cyclomatic Complexity?

Cyclomatic complexity is a metric that measures the number of logical branches in your code. In the example above, the code has a cyclomatic complexity of 2 due to the null check. Now, imagine if the code included multiple null checks—complexity would increase significantly even before any substantial work is done.

Additionally, if the program calls ItemView.Render() without initializing ItemView, a null reference error could be easily thrown, leading to runtime exceptions.

Visual Representation

Here’s a class diagram that illustrates this scenario:

Item
+String FirstName
+String LastName
ItemView
Program
+ItemView.Render()

Now, let’s introduce the concept of a NullItem class, which can be used in place of a null Item. By implementing both Item and NullItem as types of IItem (an interface), we can avoid null checks altogether.

Item
+String FirstName
+String LastName
«Interface»
IItem
+String FirstName
+String LastName
NullItem
+String FirstName
+String LastName
ItemView
Program
+ItemView.Render()

Implementing the Null Object Pattern

It’s a common convention to prefix null object classes with “Null”. In this case, NullItem would provide a default implementation, ensuring that ItemView never deals with a null value.

Here’s how the code would look using the Null Object pattern:

public class ItemView
{
    private readonly IItem _item;

    public ItemView(IItem item)
    {
        _item = item;
    }
}

With this approach, the cyclomatic complexity drops to 1, resulting in cleaner and more maintainable code.

Summary