Null Object Pattern

Avoid Prolific Null Checks In Your Code

The Null Object Pattern was described in the Gang of Four’s Design Patterns book. The intent of this pattern is to reduce the need to add checks and special behavior for handling null instances of certain variables that tend to propagate through applications. Rather, identify the behavior that should occur when a null is encountered, encapsulate this behavior into an instance of the type in question, and define this instance as a special, constant value of that type.

For instance, consider a call center application that looks up customers based on their phone number:

C#

1

2

3

4

5

6

publicCustomer GetByPhoneNumber(stringphoneNumber)

{

return_customerRepository

.List(c=>c.PhoneNumber==phoneNumber)

.FirstOrDefault();

}

Now imagine that elsewhere the application needs to display some details about the customer that was found, such as their total number of orders and amount spent. The application will need to be careful to check for null:

C#

1

2

3

4

varcustomer=GetByPhoneNumber(phone);

intorderCount=customer!=null?customer.OrderCount:0;

decimaltotalPurchase=customer!=null?customer.TotalPurchase:0m;

This kind of code gets even more verbose if full if blocks are used, and it’s very easy to miss a check, in which case a runtime null reference exception is likely.

To implement the Null Object Pattern, an instance of Customer is created to represent the case of a “not found” customer:

1

2

3

4

5

6

7

publicclassCustomer

{

publicstaticCustomer NotFound=

newCustomer(){OrderCount=0,TotalSales=0m};

// other properties and behavior

}

Then, wherever you would have a method that could return a null Customer, have it return the static instance instead:

1

2

3

4

5

6

7

8

publicCustomer GetByPhoneNumber(stringphoneNumber)

{

varcustomer=_customerRepository

.List(c=&gt;c.PhoneNumber==phoneNumber)

.FirstOrDefault();

if(customer==null){returnCustomer.NotFound;}

returncustomer;

}

Once the Null Object Pattern is in place, there is no need to even have the local variables (orderCount, totalPurchase) shown in the example above, as they only existed because the customer instance might be null. Likewise, their null checks aren’t needed – overall the client code is simpler, and probably has less duplicate code, since frequently these kinds of null checks proliferate throughout the code base (this is symptomatic of the fact that nulls violate the Liskov Substitution Principle).