Wednesday, April 13, 2011

Null Object Pattern

Intent
The intent of a Null Object is to encapsulate the absence of an object by providing a substitutable alternative that offers suitable default do nothing behavior.

How should it be used in already defined classes in java?

Joshua Bloch in his excellent book Effective Java (2nd Edition) gives advice that you should never return null collection/map/array from your code i.e. instead of such code:

public List<String> returnCollection() {  
  //remainder omitted  
  if (/*some condition*/) {  
    return null;  
  } else {  
    // return collection  
  }  
}

use this pattern:

public List<String> returnCollection() {  
  //remainder omitted  
  if (/*some condition*/) {  
    return Collections.emptyList();  
  } else {  
    // return collection  
  }  
}

So instead of returning the null collection, we are returning a empty list. Similar story goes for array or string. This basically prevents caller of your code to get NPE / Null Pointer Exception while trying to do things like this:
if (obj.returnCollection().size() > 0) {

When to use Null Object Pattern?
  • an object requires a collaborator. The Null Object pattern does not introduce this collaboration—it makes use of a collaboration that already exists
  • some collaborator instances should do nothing
  • you want to abstract the handling of null away from the client
As we saw from examples above, we have a clear idea, that it should be used to avoid NPEs.

Implementation
The participants classes in this pattern are:
AbstractClass - defines abstract primitive operations that concrete implementations have to define.
RealClass - a real implementation of the AbstractClass performing some real actions.
NullClass - a implementation which do nothing of the abstract class, in order to provide a non-null object to the client.
Client - the client gets an implementation of the abstract class and uses it. It doesn't really care if the implementation is a null object or an real object since both of them are used in the same way.

Example of Null Object Pattern
Here is the example - let's assume that you have an application that check whether the user is authenticated:

public class User {  
  private String username;  
  private boolean authenticated;  
  // remainder omitted  
  
  public boolean isAuthenticated() {  
    return authenticated;  
  }  
  // remainder omitted  
}

and the code that returns the reference to the User object looks like this:

public User getUser() {  
  if (/*some condition*/) {  
    return user;  
  } else {  
    return null;  
  }  
}

This way the code that checks whether our user is authenticated should look like the following snippet:
if (obj.getUser() != null && obj.getUser().isAuthenticated() {  
  // allow  
}  
// remainder omitted

Checking whether the object is null is not only a boilerplate code but it can also give you a lot of bugs e.g. if you forget to check whether the object is null. Also this code doesn't looks clean as well, so we have to think - object is not null , if not it is authenticated. This hampers the business logic, because we have to just see that whether user is authenticated or not.

And here is the Null Object who can help you:

public class NullUser extends User {  
    
  public static final NullUser INSTANCE = new NullUser();  
  
  public static NullUser getInstance() {  
    return INSTANCE;  
  }  
  
  @Override  
  public boolean isAuthenticated() {  
    return false;  
  }  
  
  private NullUser() {  
  }  
}

Now the authentication function becomes -

public User getUser() {  
  if (/*some condition*/) {  
    return user;  
  } else {  
    return NullUser.getInstance();  
  }  
}

plus cleaner client code:

if (obj.getUser().isAuthenticated() {  
  // allow  
}  
// remainder omitted

I find this pattern very useful and really helpful. With this pattern you can really save yourself a lot of NPEs.

Still the question is whether User should be a class or an interface and then whether NullUser should extend the base class or implement the user's interface. But I will leave this decision for your consideration. In this case we chose to extend the base class though.

Null Object Pattern and other patterns
Null Object and Factory
The Null Object design pattern is more likely to be used in conjunction with the Factory pattern. The reason for this is obvious: A Concrete Classes need to be instantiated and then to be served to the client. The client uses the concrete class. The concrete class can be a Real Object or a Null Object.
Null Object and Template Method
The Template method design pattern need to define an abstract class that define the template and each concrete class implements the steps for the template. If there are cases when sometimes template is called and sometimes not then, in order to avoid the checking a Null Object can be use to implement a Concrete Template that does nothing.
Removing old functionality
The Null Object can be used to remove old functionality by replacing it with null objects. The big advantage is that the existing code doesn't need to be touched.

Conclusion
The Null Object Pattern is used to avoid special if blocks for do nothing code, by putting the “do nothing” code in the Null Object which becomes responsible for doing nothing. The client is not aware anymore if the real object or the null object is called so the 'if' section is removed from client implementation.

No comments:

Post a Comment

Chitika