Implementing Null Object Design Pattern in C#

A look at the popular design pattern

Rikam Palkar
Better Programming
Published in
4 min readMar 8, 2022

--

Photo by Rich Tervet on Unsplash

Folks, we have come a long way. From object != null;to object ?? object.value; and now back at object != null;.

Why do we need this pattern?

We all are familiar with null checks. We use it so often that now we don’t even think before using it. Our brain starts coding it from muscle memory.

person != null;person ?? person.name;

The T-Rex in the mirror starts getting bigger and bigger with a number of null checks. Look at the following condition, it’s so not easy on the eyes. and you will find such null checks throughout the application.

If(object1 != null && object1.value == true && object2 != null && object2.value == “success” || object3 == null)

With the help of a null object design pattern, we can finally start bringing some sense to our null checks. Instead of validating null checks, we can show some default behavior or do absolutely nothing. With this, we can manage to keep the client’s code cleaner.

What is a null object design pattern?

Look at listing 1, the client, class SmartPhoneSale below:

In this case, the code might throw a null exception.

The client class SmartPhoneSale can access the dependency class SmartPhone with the reference variable of DependencyBase interface ISmartPhone and if SmartPhone is null we can replace that null behavior with NullObject class DefaultSmartPhone.

In the following example, a class DefaultSmartPhone is providing do nothing or default implementation of class SmartPhone and will be used whenever we need to check null values.

Let’s see how it looks conceptually:

UML design for null object design pattern
  • class SmartPhoneSale: This is a client class, which uses the design pattern. In our example, SmartPhoneSale has a main method that will execute the methods of a null object. You can see the implementation of class client in listing 1.
  • interface ISmartPhone: Also known as DependencyBase interface. This is an interface that has a method definition that the client needs to use. In our example, the client needs methods: 1. SetName() and 2. SetPrice().
  • class SmartPhone: is the dependency class. This class is an actual dependency that the client requires. This class has business logic which is needed by the client.
  • class DefaultSmartPhone: is The NullObject class. This is the null object class that can be used as a replacement instead of class SmartPhone to replace null checks. It contains no functionality but implements all of the members defined by the interface ISmartPhone.

The Implementation

As per our concept, we have already implemented a client class in listing 1.

Now we need abstraction in our code. Let’s go ahead and create that interface.

The DependencyBase interface, interface ISmartPhone is given below:

Next stop, concrete classes. One is for default initialization and another for our logic.

Let’s create a default class.

Listing 3: class DefaultSmartPhone a.k.a the NullObject class is given below:

As you can see, we are doing nothing here, other than just assigning an object to do something when it goes into a null state.

Listing 4: The Dependency class, class SmartPhone:

We are all set, now let’s make a few changes in the client class with the newly implemented null object design pattern.

Listing 5: The class client making use of null object design pattern:

As you can see, when the object for smartPhone is null, we are assigning him the default class’s instance.

Output when smartPhoneInstance is null:

Output when a SmartPhoneInstance is not null. Just uncomment line number 7 in listing 5.

This is the simplest design pattern to learn. It is a good practice to work with design patterns that adds extensibility to code. It gives you a broad idea of object communications.

I sincerely hope that you enjoyed this article and that you’re inspired to apply what you’ve learned to your own applications.

--

--