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: May 11, 2015 @ 1:00 p.m. ET / 10:00 a.m. PT One of the languages that have always been supported with the Intel® RealSense™ SDK (Software Developer Kit) is JavaScript, specifically so that web-enabled apps could be created. Come hear from Intel Expert Bob Duffy as he reviews his own little "space shooting" game where the orientation of your face controls the aiming reticle to help teach developers how to write apps and games in JavaScript that can use facial and gesture …

  • You may not realize the complexity you could be creating when developing mobile apps – many companies don't initially. You could be doubling your IT costs for development and delivery; not to mention, risking sales, productivity and brand satisfaction. Read this IBM-commissioned Forrester Study to understand the key cost drivers of mobile app delivery -- for both customer-facing and enterprise applications. Find out how you could lower costs and increase success with the right strategy and investment.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date