Rice University - Comp 212 - Intermediate Programming
Fall 2001
Lecture #29 - Null Object Pattern
The Null Object
says, "Just because I don't have anything and don't do anything, it
does not mean that I am not smart.
By not having anything, I don't take up
much resource and can be shared among many.
By not doing anything, I am
doing the right thing."
Today's Topics
- Discussion of programming project #3: Tournament Tree.
- Null-Object Pattern.
Avoid checking for null
In much of the current programming practice, the special value null
is often used as a flag to represent a gamut of different and often disconnected
concepts such as emptiness and falseness. This can result in a lot of
confusion and complex control structures in the code. In our view, null
should only be used to denote the non-existence of an object. null
is not an object and has no "intelligence" (i.e. behavior) for other
objects to interact with. Therefore, whenever we work with a union
of objects and discover that one or more of these objects may be referencing a null
value, we almost always have to write code to distinguish null
as a special case. To avoid this problem, we should think of adding a
special object, called the null object, to the union with
appropriate behavior that will allow us to treat all object references in a
consistent and uniform way, devoid of special case consideration. This
design pattern is called the null object pattern.
Examples
- schemeFW.EmptyList is the null object in
the design of the immutable list framework.
- lrs.EmptyNode is the null object in the
design of the mutable list framework.
- the "unknown" team in the Tournament tree is the null object.
- In the sample code for the Hangman view (see below), we use an IPaintAdapter
to paint the Hangman body parts. At the time the code was written, we had
not seen the null object pattern. yet. We had to write an if statement to check the IPaintAdapter
for nullity before asking it to paint.
public class HangmanFrame extends JFrame {
IPaintAdapter _paintAdapter;
// initially null!
JPanel displayPanel =
new JPanel() {
public
void paintComponent(Graphics g) {
super.paintComponent(g);
//
Code elided…
if(_paintAdapter != null) { //
Nullity check!
_paintAdapter.paint(g);
}
}
};
// Code elided…
}
We can now apply the null-object pattern to IPaintAdapter by initializing _
paintAdapter to an anonymous inner class that does nothing and avoid
checking for nullity completely.
public class HangmanFrame extends JFrame {
IPaintAdapter _paintAdapter
= new IpaintAdapter() { // Anonymous inner class
public
void paintComponent(Graphics g) { // does nothing!
}
}
JPanel displayPanel =
new JPanel() {
public
void paintComponent(Graphics g) {
super.paintComponent(g);
//
Code elided…
_paintAdapter.paint(g);
// No nullity check!
}
};
// Code elided…
}
- In the above examples, there is no ifs, no buts, no conds, no switches, no
nothing! Only objects requesting other objects to do their jobs. The
underlining polymorphism machinery directs the program's control flow. The
programmer is liberated from writing control statements. The program as a
whole is glued together by the architecture of the object structure and not
by contorted control code, and thus is more robust and easier to maintain.
dxnguyen@cs.rice.edu
Copyright 2001, Dung X. Nguyen - All rights reserved.