Beginner’s Tutorial on Understanding and Implementing Null Object Pattern in C#

In this article we will try to understand the Null object pattern and see how this pattern can help us to write more robust code. We will implement a contrived example to demonstrate this pattern.

Background

There is no developer in the world who has not encounters a “ Null reference exception” in his development career. What is this exception? Well this exception simply tell that we are trying to access to deference a variable with NULL value. Which brings another question, what is a NULL value? NULL in most programming languages indicates the absence of a value. For any variable, if the value is NULL, it would mean that there is no value associated with that variable and thus the caller should not perform any operation using this variable.

From a language perspective, NULL is very important and does makes sense as there are scenarios where we want to represent the absence of value in a variable. But from the code maintainability perspective, it would mean that whenever we are getting an object from another module/class/service, we should always check if it is null or not before using this variable. This could lead to more complex and unmaintainable code.

Now the Null object pattern try to ease this problem. This pattern suggests that whenever we have dependent modules returning objects to each other, we should always return an object. The absence of a valid value should also be represented as a special object in this case. This can be implemented creating and returning instances of a concrete class that implements the same interface the valid class implements. but it will do nothing whenever any operations are performed on it. What this will do is that it make the calling code much simpler since the calling code will not have to check for null but simply call the methods on the return object.

If we try to visualize the Null object pattern, it will look something like following.

UML

  • Client. This class that requires the instance of an object to use.
  • DependencyBase. This is an interface that all the concrete classes(that could be returned to client) will implement.
  • Dependency. This is the actual concrete classes(that could be returned to client)
  • NullObject. This is our Null Object class. This will be returned to the client whenever we want to return NO-VALUE or absence of value to the client. In other words, this is the class that will be returned to the client in all the scenarios where otherwise we would have returned null. Its important to note that this class will implement the DependencyBaseinterface but will provide a DO-NOTHING implementation for the interface since absence of value means no operations should be possible.

Now before we move on to see how this could be implemented, let us discuss when it makes sense to use this pattern. If we try to use this pattern for all possible classes in the system, we will end up increasing the complexity of the system rather than reducing it.

It only makes sense to use this pattern when we have some class that is expecting another class and is using some sort of factory, service locator or strategy to get the instance of this class. This will ensure that whenever a dependency is being pulled from external module, we don’t have to worry about the NULL values but rather the external system will return a NULL Object which can safely be used for do nothing type of operations.

Using the code

Now let us look into a very contrived example to understand this pattern. First let us try to understand the problem by not using a Null Object.

In this example, we will ask the user to select a shipping method(yes yet another e-commerce example). Based on the users selection, we will select the appropriate shipping strategy and pass it to the OrderProcessorclass. OrderProcessorclass will use it to schedule the shipping. So lets start by looking at our interface that represent the shipping strategy i.e. IShippingStrategy.

Once we have this interface ready, lets look at the concrete classes for shipping. The reason for these separate classes is because each of this class will call a web service of the respective shipping service provider to schedule a shipping(In real world, here we are just logging method call on console).

Now lets look at our OrderProcessorclass which will schedule shipping using the passed in IShippingStrategy.

And finally lets look at the code that is mimicking the selection of shipping method from the user.

Now the problem we have talked about the NULL values is quite evident when we look at the OrderProcessorcode.

The order processor is checking whether the passed strategy is null or not. If it is not then some action is being taken otherwise some different action. Now there are two issue with this

  1. The code is messy due to all these null checks and
  2. If an invalid shipping method is selected something needs to be done apart from just logging. Which would mean that this invalid case handling logic will also come in the OrderProcessorclass which is direct violation of Single Responsibility Principle.

Welcome Null Object

So to avoid this problem, let us introduce a Null Object on our application. Lets call this class InvalidShippingStrategy

Now with this null object in place, we need to modify the strategy creation code to cater to the invalid scenario too.

And the best part is that the OrderProcessorwill not have to worry about the invalid shipping selection at all. All the code to handle the invalid shipping method can be put inside our Null Object i.e. InvalidShippingStrategyclass.

This represents a very basic implementation of Null Object pattern.

Singleton should help

Now when we look at our Null Object, its behavior is same irrespective of any number of instances we create for it i.e. It will handle the NO-VALUE-DO-NOTHING scenario. So does is really makes sense to have multiple instances of this class. Perhaps not. So an optimization could be to make this class singleton.

we need to modify the strategy creation code to cater to the invalid scenario too so the program.cs will now do something like:

Now we have a singleton Null object and thus only one instance of this Null object will be there in the system and thus some performance gain.

Note: The important thing to remember about this pattern is that it should be used whenever we see multiple classes collaborating by passing objects. Some examples for this could be strategypattern, factorypattern, Service Locator, Commandpattern, RepositoryPattern etc. Having this pattern for all classes is not a good idea and could lead to more complex code.

Points of interest

In this article we have looked at Null Object pattern. We have seen how this pattern can make the calling code much cleaner with no null checks. We have also looked at a very basic(and not so real world) implementation of the pattern. This has been written from beginner’s perspective. I hope this has been informative.

Download sample code from here: NullObjectDemo