views:

78

answers:

5

The NullObjectPattern is intended to be a "safe" ( neutral ) behavior.

The idea is create an object that don't do anything ( but doesn't throw NullPointerException either )

For instance the class defined as:

class Employee {
    private String name;
    private int age;
    public String getName(){ return name; }
    public int getAge()    { return age;  }
}  

Would cause a NullPointerException in this code:

 class Other {
      Employee oscar;

      String theName = oscar.getName(); // NPE

 }

What the NOP says, is you can have an object like this:

 class NullEmployee extends Employee {
      public static final  Employee instance = new NullEmployee(); 
      public String getName(){ return ""; }
      public int getAge()    { return 0;  }
 }

And then use it as the default value.

 Employee oscar = NullEmployee.instance;

The problem comes, when you need to repeat the code for every class you create, then a solution would be to have a tool to created it.

Would it be feasible/reasonable/useful to create such a tool or to use it ( if existed )?

Perhaps using AOP or DI the default value could be used automagically.

+2  A: 

I am not sure this is a good idea. A "nullObject" may be useful and make perfect sense in some cases, but having this for every class is an overkill. Especially because this could potentially make some bug (or gaps in analysis) very hard to diagnose.

Also, what about 3rd part libraries that return new objects? Would you put some kind of "interface" in front of these so that in case they return null you will substitute an appopriate flavour of nullObject?

You mention that you are trying to automate this - wouldn't some cases require an actual design decision to return an appropriate value? I.e., suppose you have an Image object, and it returns a "ImageType" (an Enumeration for .gif, .jpg etc.)

In this case, the ImageNullObject should return... "IMAGETYPE.GIF"? "IMAGETYPE.UNKNOWN"? Null?

p.marino
A: 

I'd think it would be tricky to autogenerate functional null objects. (You could of course create shells that you then go and fill in the implementation itself).

As a quick example - what is the null functionality for a method that returns an int? Should it return -1, 0, or perhaps some other value? How about something that returns a String - again, is null or "" the correct choice? For methods returning some other class - if it's one of your own classes then presumably you could use the Null Object for that class, but how would you access it? Perhaps you could make every class you write implement some interface with an accessor for the null object, but is it worth it?

Even with methods that return void, it's not always the case that the null functionality is to simply return. Some classes, for example, might need to call a method on a parent/delegate object when they've done their own thing (which in this case would be a no-op) in order to preserve the invariants of the class.

So basically - even to implement "null" behaviour, you have to be able to infer what this behaviour is, and I expect this is far too advanced for a tool to do itself. Perhaps you could annotate all your methods with something like @NullReturns(-1), and have a tool pick these up and form the null object implementation, but even that won't cover every situation and you may as well write the object directly instead of writing all its functionality in annotations.

Andrzej Doyle
+2  A: 

I think you are just begging to push the error conditions down a layer.

When an application asks for an object, and it is null, then you need to deal with that condition, not just hope it is ok. If the object is null, and you try to use it, you will get errors, so why force all that error checking on the rest of the code?

Randy
Not always a bad practice. Sometimes it doesn't matter. Example. You have a Request class, it has an optional property, Approver, which contains a null or a Person object. When saving the Request, you'll have a line of code that references Approver.ID. Approver could be null, and you'd have to check, and replace it with a default. This could be happening on dozens of objects that reference an optional Person. When it doesn't matter, let the code carry on indifferent to whether it's a NullPerson object or a real Person object. When you NEED a real Person, you check the objects type.
Chad
+3  A: 

To me, the Null Object pattern feels like a placebo. A real object and a null object may have completely different meanings, but act very similar. Just like a placebo, the null object will trick you into believing there's nothing wrong, but something could be very wrong.

I think it's a good practice to fail early and fail often. In the end, you'll want to distinguish between a real object and a null object somewhere, and at that point it would be no different from checking against a null pointer.

From the Wikipedia article:

The advantage of this approach over a working default implementation is that a Null Object is very predictable and has no side effects: it does nothing.

It won't point out any problems either. Think of what will happen when a null object travels all the way through your application. Then, at some point, your application expects certain behavior from the object, which the null object implementation fails to deliver. At that point your application may crash or enter an invalid state. You'll have a very hard time tracing the origin of the null object. A null pointer would have thrown an exception right at the beginning, drawing your attention directly to the source of the problem.

The only example the Wikipedia article gives, is that of an empty collection instead of null. This is a very good practice, but a lousy example of the null object pattern, because it's dealing with a collection of objects, instead of a single instance.

In short, I'm sure it's feasible to create null object implementations for all your classes, but I strongly recommend against it.

Niels van der Rest
A: 

Except for testing, I generally call this type of concept coding for Slop. It's the opposite of fail-fast, you are postponing any chance of locating a state you did not code for.

The main point here is why is it possible for your object to return a value that's not in the method's contract? When you wrote out the method's contract in the Javadocs, you either said it could or couldn't return null, right? So if you can return null, it's important. If you can't return null, it's important.

Also, If the object reference you are using can be null then that's a significant value and you shouldn't EVER be dipping into code that might access that object's methods.

On top of that, use final every chance you get. If a member variable is assigned to final when it's created, the reference can never be null. Remember that it's allowed to specify a member as final and not assign it:

final MyObject obj;

as long as it's assigned in the constructor (and Java will do branch checking for you to assure that it's assigned in every branch before it's used).

If you can make all your members final, this problem should never occur.

Except for emergency patches and testing I honestly can't see any excuse for this kind of coding except "I don't understand the code and I think this isn't working right but I don't want to try to understand it"--which is not, IMO, a valid excuse for an engineer.

Bill K