This is one of those "I used to hate it, now I love it" things. I used to think things should only be nullable for a reason, and you should always care if something is null - always. Null is the extra state beyond all others and I used to think it was very important to keep track of this all the time, in every layer of my application.
Later, I worked on a project (at SNSC) and was exposed to the CSLA framework. The Null object pattern was used a lot and I kind of quickly grew to appreciate it (concentrating my policy on nulls in one place.)
Over the years I have gold plated the way I use this pattern and adapted it for what I am doing at the time. I've come to recognize the following as desirable features for Null Object classes:
- There should be a "tag" interface for the null object and an implementation. That way, when nulling for a subclass of something else, I can inherit the subclass and implement multiple null object tag interfaces (see below.)
- They should have a static accessor to a singleton instance, so you don't have to new them up all the time, and get reference equals right.
- They should have good ToStrings, so it's really obvious when you are looking at them in a debugger.
- For extra credit, override any mutator or method that changes state to implement your policy: either raise an exception to catch bugs, or just silently ignore.
So, here is a typical null object implementation I have:
Some code for EmptyManagerAssignment:
public interface EmptyManagerAssignment : EmptyAssignment { }
public class EmptyManagerAssignmentImpl : ManagerAssignment, EmptyManagerAssignment
{
private static EmptyManagerAssignmentImpl _instance;
/// <summary>
/// Initializes a new instance of the EmptyManagerAssignmentImpl class.
/// </summary>
public EmptyManagerAssignmentImpl()
: base()
{
}
public static EmptyManagerAssignmentImpl Instance
{
get
{
if (_instance == null)
_instance = new EmptyManagerAssignmentImpl();
return _instance;
}
}
public override string ToString()
{
return "{no Manager Assignment}";
}
public override int GetHashCode()
{
return ToString().GetHashCode();
}
}
In this case, the defaults the base class (ManagerAssignment) sets are just fine for the null object, but if I needed say the Name property of the null objects to be different (say I wanted to display "No Assignment" wherever I had the name of a ManagerAssignment in my UI) I would do this in the null object's constructor.
I can then use it like:
public Program()
: this("", new EmptyStrategyImpl(), new EmptyIndexImpl(), new EmptyManagerAssignmentImpl(), "New Program")
{
}
or
if (HoldingsAssignment is EmptyAssignment /* or EmptyManagerAssignment...either way */)
{
...
}
The static accessor thing ("Instance" above) is something I can't decide on. I like the fact that I'm not slamming the heap with a crap load of null objects, and I really like the identity implications of using a single instance of each null object type. But the side effect is that one object could mess up the null object for everyone else:
if (foo is EmptyAssignment)
foo.Name = "Look at me! I just messed up the Null object for everyone!";
Because I still like the singleton, I keep waffling back and forth on is whether or not to do something special when someone tries to update the null object:
public override string AccountNumber
{
get { return base.AccountNumber; }
set { throw new NotImplementedException("Can't update an Empty Manager Assignment...jackass"); }
}
or
public override string AccountNumber
{
get { return base.AccountNumber; }
set { /* nop */ }
}
It helps catch bugs, but most of those types of bugs I catch with unit tests anyway. Besides, it's a heck of a lot of work to implement overrides for everything. I could use a code generator, then regenerate all the time. Been there. Done that. Sux.
Therefore, laziness wins. I have a singleton null object. I don't check every mutator. I have a nice simple code rush template.
One final thing I will add: When using this pattern with NHibernate, I don't want NHibernate storing these null objects in the database, so I currently like to do it like this:
- Have a field that is nullable. Tell NH about that, not the property:
<many-to-one name="_holdingsAssignment" column="HoldingsAssignmentID"
access="field" cascade="save-update" />
- Have a property that hides this nullable field from the rest of my classes:
public virtual ManagerAssignment HoldingsAssignment
{
get
{
if (_holdingsAssignment == null)
return EmptyManagerAssignmentImpl.Instance;
return _holdingsAssignment;
}
set
{
if (value is EmptyAssignment)
_holdingsAssignment = null;
else
_holdingsAssignment = value;
}
}
For a long time I've been meaning to check and see if there is some way to specify a surrogate for null in NHibernate, for reference types (I know how to do it with scalars.)
Does anyone else use this pattern like this? Any tricks? Does this make me look like I have too much time on my hands?