Is this dialog (exception) familiar to you?
Okay, maybe you haven’t seen this screen in particular but apart from the troubleshooting tips you should have seen it.
Few days ago I have discovered the Null object pattern (NOP) and its usefulness. Kick me, punch me or even stone me to death cause I haven’t known it so far Still I would like to write a quick note about it as not everyone might be aware of it.
If it’s possible for a variable to be null, you have to remember to surround it with null test code so you’ll do the right thing if a null is present. Often the right thing is same in many contexts, so you end up writing similar code in lots of places - committing the sin of code duplication. - Martin Fowler
What does that exactly mean? It means the following:
if (Product.Creator == null) {
Debug.WriteLine("unknown");
} else {
Debug.WriteLine(Product.Creator);
}
If we have a Creator
property of a Product
and it may be null (to indicate an unknown creator) we need to do a null check everywhere we wanna display the creator. I would call it boring code duplication. And that’s where the NOP joins our game.
Let’s create a user instance which represents the actual “unknown” user so we can get rid of the odd null check. Best to achieve that is to sub class our User
into an Unknown
user. The following diagram illustrates this simple approach. btw see Customers equal to users :))
Figure 1 - Patterns of Enterprise Application Architecture, Martin Fowler
As you can see we are even able to provide different types of “null” users such as “Missing” and “Unknown”. That allows us to assign a human readable name to those users (e.g. assign in the sub class’ constructor) and we are still able to check if a given user is unknown (if necessary):
if (Product.Creator is UnknownUser)
Okay, enough general theory about the pattern itself. You might ask how does the whole thing fit into NHibernate? Persistence is the magic word. If our users are persisted then the “unknown” users gets persisted as well. That’s probably not what we want. We wanna keep our data storage clean containing only “real” users. Michael Cromwell points that out in one of his articles:
This then has its own problems because if it’s a user editable object you don’t really want them to be able to change/delete this data so it becomes a special case that will need to be locked for editing/deleting. - NHibernate & Null Object Pattern: The Options, Michael Cromwell
Correct! We don’t want to exclude this user in all our queries and take care of these “special case users”. What he suggests is to handle that case directly in the getter and setter of the property. In case a null is assigned he returns an “NotAssigned User”. In our particular example the solution would look the following:
protected User _creator;
public User Creator {
get {
return _creator ?? new UnknownUser();
}
set {
if (value is UnknownUser)
_creator = null;
else
_creator = value;
}
}
I am happy! This looks like a nice OO solution to me. The “unknown user” won’t be persisted, a null reference will be stored instead. Important: This works fine for one “unknown user type”. However, keep in mind that if we have more than one “unknown user type” (see Figure 1) than it might be necessary to persist those users in order to be able to differentiate between them.
Haven’t used it so far but will in my next projects. Anyone who is interested into more practical details might read How to avoid “!= null” statements in Java?.