Null Objects: Are they evil?


Hi, this is my first blog entry ever, and it has taken me a while before I decided to write. I’m a programmer by profession and passion, and I love doing what I do. For my first entry, I wanted to blog about something close to my heart, and Null Objects came to mind. You must be wondering, why I say null objects are evil. Not always, but they can be and most certainly will be if left unchecked.

On many projects I worked on, we always had problems with null objects. The constant checking for null-ness before access a property or behaviour, made our code somewhat unreadable, not elegant and just a pain to maintain. As you might already guessed, many defects were raised relating to this and became a recurring issue.

This is best illustrated with an example. Consider these 3 classes, Company, Customer, and Membership.

public class Company
{
    public Customer Customer { get; set; }
}
public class Customer
{
    public string Name { get; set; }
    public Membership Membership { get; set; }
}
public class Membership
{
    public int MembershipNumber { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}
If we were to access the StartDate property on the Membership object, we will need to check if the Customer object is null, and also check if the Membership object is null. That’s a lot of checking…and imagine doing this for
deeply nested classes. Getting object’s properties is especially common when wiring up your data in the objects to your User Interface controls. It might look something like this.
/// <summary>
/// this is an example how we would normally do without null /// object
/// </summary>
public void ExampleWithoutNullObject()
{
    // getting properties
    string customerName;
    int membershipNumber;
    DateTime membershipStartDate;
    DateTime? membershipEndDate;

    Company company = new Company();
    Customer cust = company.Customer;

    if (cust == null)
    {
        customerName = "New Customer";
        membershipNumber = 0;
        membershipStartDate = DateTime.MinValue;
        membershipEndDate = null;
    }
    else
    {
        customerName = cust.Name;
        if (cust.Membership == null)
        {
            membershipNumber = 0;
            membershipStartDate = DateTime.MinValue;
            membershipEndDate = null;
        }
        else
        {
             membershipNumber =
                cust.Membership.MembershipNumber;
             membershipStartDate = cust.Membership.StartDate;
             membershipEndDate = cust.Membership.EndDate;
        }
    }
}

So how do we get around this problem? Introducing the Null Object pattern, illustrated from the book written by Martin Fowler, Refactoring: Improving the Design of Existing Code.

The essence of this pattern is to remove all null checks by replacing null values with null objects. The motivation here is that when we ask the Company object for it’s Customer object to invoke a property/behaviour, we should not need to check for null-ness. This can be accomplished by polymorphism. Here goes the refactoring…

Step 1: Modify the Membership object and create a subclass called NullMembership.

public class Membership : INullableObject
{
    public virtual int MembershipNumber { get; set; }
    public virtual DateTime StartDate { get; set; }
    public virtual DateTime? EndDate { get; set; }

   #region INullObject Members

   public virtual bool IsNull
   {
       get { return false; }
   }

   #endregion

   public static Membership NullMembership()
   {
       return new NullMembership();
   }
}

public class NullMembership : Membership
{
    public override int MembershipNumber
    {
        get
        {
             // return your default value when not known
             return 0;
        }
        set
        {
            ;
        }
    }

    public override DateTime StartDate
    {
        get
        {
            // return your default value when not known
            return DateTime.MinValue;
        }
        set
        {
            ;
        }
    }

    public override DateTime? EndDate
    {
        get
        {
            // return your default value when not known
            return null;
        }
        set
        {
            ;
        }
    }

    public override bool IsNull
    {
        get
        {
            return true;
        }
    }
}

Step 2: Modify the Customer object and create a subclass called NullCustomer.

public class Customer : INullableObject
{
    public virtual string Name { get; set; }
    private Membership membership;

    public virtual Membership Membership
    {
        get
        {
            if (membership == null)
            {
                return Membership.NullMembership();
            }
	      reuturn membership;
        }
        set
        {
            membership = value;
        }
    }
    #region INullObject Members

    public virtual bool IsNull
    {
        get { return false; }
    }

    #endregion

    public static Customer NullCustomer()
    {
        return new NullCustomer();
    }
}

public class NullCustomer : Customer
{
    public override string Name
    {
        get
        {
            return "New Customer";
        }
        set
        {
            ;
        }
    }

    public override Membership Membership
    {
        get
        {
            return Membership.NullMembership();
        }
        set
        {
            ;
        }
    }

    public override bool IsNull
    {
        get
        {
            return true;
        }
    }
}

As you can see, we have made the Customer’s and Membership properties virtual, and created a subclass called NullCustomer and NullMembership. A NullCustomer will know what kind of default values to return, for example the Name property will return “New Customer”.

Step 3: Modify Company object to return a NullCustomer.

public class Company
{
    private Customer customer;
    public Customer Customer
    {
        get
        {
            if (customer == null)
            {
                return Customer.NullCustomer();
            }
            return customer;
        }
        set { customer = value; }
    }
}

With this, the refactoring is complete. The Company object will return a NullCustomer, if one has not been created yet. If you’ve been looking at the code, you would have noticed there’s a INullableObject interface in the refactoring. This is optional, but often good practice to have an interface for abstraction as well being able to use it as a testing interface.

Remember, it’s always better to program to an interface (or contract), than an implementation.

Finally, after the refactoring, let’s have a look at the final results. Now things become as simple as this.

/// <summary>
/// this exampe here shows how easy it is and clean to get 
/// properties with Null Object 
/// </summary>
public void ExampleWithNullObject()
{
    // getting properties
    string customerName;
    int membershipNumber;
    DateTime membershipStartDate;
    DateTime? membershipEndDate;

    Company company = new Company();
    Customer cust = company.Customer;

    // no longer need to check for null, because the null  
    // object takes care of it internally.
    customerName = cust.Name;
    membershipNumber = cust.Membership.MembershipNumber;
    membershipStartDate = cust.Membership.StartDate;
    membershipEndDate = cust.Membership.EndDate;
}

With the use of Null Object pattern, we no longer require to check for null, and just confidently access these properties. Sweet. 🙂

Download this example (VS2008): NullObjectPattern.zip

Share this post : del.icio.us it! digg it! dotnetkicks it! live it! technorati!
Advertisements

3 Responses to “Null Objects: Are they evil?”

  1. Using Factory Method Pattern with System.Activator « Code Blitz Says:

    […] it by creating a NullControl (a container that displays my error message) , which follows the Null Object pattern. If your rather throw an Exceptioninstead, that’s perfectly fine, just remember to handle it […]

  2. Review my code please « Code Blitz Says:

    […] are not fun to play with, but there are ways to handle that. I’m inclined to believe that null objects can become evil when misued. In C#, the null coalescing operator is very useful when you need to specify an alternative value […]

  3. Null Object Pattern for DateTime in .Net « Fragmented Thoughts Says:

    […] to the evil nature of nulls we were hesitant to allow null DateTime values to enter into our model without a really good […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: