Null Object Pattern in C#

A Null object is an object that encapsulates the absence of an object. It provides the do nothing behavior and returns the defaults. The Null object is used whenever object reference would have been null. The use of Null Object pattern simplifies the client code and makes it less error prone.

Consider a simple sales application, which verifies the customer account and check whether customer does have the gold membership. Gold members get varied benefits like discount, free shipping etc.

Below is the code snippet of the main method that gets the account details of the customers and retrieves their gold membership profile and applies all the benefits applicable to the gold members.

string userName = args[0];
string pin = args[1];
Order order = new Order();

for (int i = 2; i < args.Length; i++)
{
    order.Amount += Convert.ToDecimal(args[i]);
}

var account = AccountController.GetAccount(userName, pin);

if (account == null)
{
    Console.WriteLine("Invalid Account");
}
else
{
    var gProfile = GoldMembershipController.GetProfile(account);

    if (gProfile != null)
    {
        order.Amount -= gProfile.GetDiscount(order.Amount);
    }

    if (gProfile != null)
    {
        if (!gProfile.IsShippingFree)
        {
            order.Amount += order.GetShippingCharges();
        }
    }
    else
    {
        order.Amount += order.GetShippingCharges();
    }

    Console.WriteLine(string.Format("Total Amount: {0}", order.Amount));
}

If customer has the valid account then AccountController.GetAccount(userName, pin) returns the Account object else it returns the null. Similarly if customer has gold membership then GoldMembershipController.GetProfile(account) returns the GoldMembership object and in case user doesn't have gold membership, it returns the null.

As you can see in the above code snippet, there are lots of repetitive conditional statements that check the null reference. Conditional statements are actually written to follow different paths based on the result of the condition. In the above gold membership case we have the same flow and conditional statements are written only to check the null references. This doesn't only make the code longer and hard to understand but also very error prone as it is very easy to miss a null guard in a large program. This is the problem that Null Object pattern is trying to solve.

After implementing the Null Object pattern GoldMembershipController.GetProfile(accountId) will always return an object. In case customer doesn't have gold membership, it will return a Null Object. To implement the Null Object pattern, we will create an IGoldMembership interface. Both GoldMembership and NullGoldMembership class will implement this interface. NullGoldMembership class is a neutral class that does nothing and simply returns the defaults. We will also modify the GoldMembershipController.GetProfile(accountId) method. It will return the GoldMembership object when user has the gold membership and NullGoldMembership when user doesn't have the gold membership.

public interface IGoldMembership
    {
        decimal GetDiscount(decimal amount);
        bool IsShippingFree { get; set; }
    }

public class GoldMembership : IGoldMembership
    {
        public GoldMembership(string userName)
        {
            // get gold member profile of this user

            IsShippingFree = true;
        }

        public bool IsShippingFree { get; set; }

        public decimal GetDiscount(decimal amount)
        {
            decimal discount = 100;

            //calculate discount

            return discount;
        }
    }

public class NullGoldMembership : IGoldMembership
    {
        public NullGoldMembership()
        {
            IsShippingFree = false;
        }

        public decimal GetDiscount(decimal amount)
        {
            return 0;
        }

        public bool IsShippingFree { get; set; }
    }

public class GoldMembershipController
    {
        public static IGoldMembership GetProfile(Account account)
        {
            // if this account has gold membership 
            // return profile else return null

            if (account.Type == "GoldMember")
            {
                return new GoldMembership(account.UserName);
            }
            else
            {
                return new NullGoldMembership();
            }
        }
    }

After implementing the Null Object pattern our code of the main method will look like below:

            string userName = args[0];
            string pin = args[1];
            Order order = new Order();

            for (int i = 2; i < args.Length; i++)
            {
                order.Amount += Convert.ToDecimal(args[i]);
            }

            var account = AccountController.GetAccount(userName, pin);

            if (account == null)
            {
                Console.WriteLine("Invalid Account");
            }
            else
            {
                var gProfile = GoldMembershipController.GetProfile(account);

                order.Amount -= gProfile.GetDiscount(order.Amount);

                if (!gProfile.IsShippingFree)
                {
                    order.Amount += order.GetShippingCharges();
                }

                Console.WriteLine(string.Format("Total Amount: {0}", order.Amount));
            }

After implementing the Null Object pattern, our client side code looks much simpler now. It is not only concise but also easy to understand.

However Null Object pattern doesn't completely eliminate the use of null reference. We may still have to follow different paths based on whether object is present or absent. In those cases we will still continue to use null reference. For example, if user doesn't have a valid account we are not going to process the transaction. In that case we will simply show the error message. In those scenarios and we still continue to use and check null references like below:

            var account = AccountController.GetAccount(userName, pin);

            if (account == null)
            {
                Console.WriteLine("Invalid Account");
            }
            else
            {
                // process the transaction
            }

Happy coding!

Sajad Deyargaroo



About the Author

Sajad Deyargaroo

Sajad, MCTS, MCP, started his career developing applications in VB 4.0 and C++. His interest in programming has spanned many languages but is now focused on .Net. Nowadays, he works with AIS on Microsoft technologies and has published many articles in several magazines and web. You can send an email to sajad@programmer.net.

Comments

  • Nonetheless, this is a good article!

    Posted by CBasicNet on 10/20/2009 11:50pm

    Thanks for the article! Here is wikipedia entry about this pattern if anyone is interested.

    http://en.wikipedia.org/wiki/Null_Object_pattern

    Reply
  • You should have credited the reference where this pattern comes from

    Posted by CBasicNet on 10/20/2009 11:46pm

    You should have mentioned that you read about this pattern from the code refactoring book by Martin Fowler or some other source. Null Object Pattern is extremely useful when you use to chain objects returned by methods or overloaded operators, to call other methods, especially XML parsing.

    Eg, string szAuthor = xmlfile["library"]["book"]["author"].GetString();

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds