Your Guide to Design Patterns – Null Object Pattern

Design Patterns - Null Object Pattern

In the past few weeks, we’ve covered design patterns from the Gang of Four (GoF) book “Design Patterns: Elements of Reusable Object-Oriented Software”.

The GoF book is a highly influential book, often seen as the start of the software design patterns movement. This has led many people to believe that the GoF book is the “gospel” of design patterns, and that its 23 patterns are the only “true” patterns.

Nothing can be further from the truth! For whatever reason, the four authors merely happened to document those 23 patterns. Those reasons could have been as simple as publishing deadlines, or a limit on the number of pages, or even that they were tired of writing.

Many patterns exist outside the GoF book. In this article we look at a simple but useful design pattern that isn’t in the GoF book: the Null Object pattern.

Remember that a pattern is a proven solution to a recurring problem in a specific context. As the context changes, so do the patterns. Every context has its own recurring problems and its own elegant solutions.

Patterns should be used as examples of good design. They teach us how to apply important object-oriented principles. They definitely should not be viewed as gospel or dogma. Patterns are tools in software engineering.

The Null Object Pattern

As most Java programmers know, we often get NullPointerExceptions when we are developing and testing our code. We generally have to test for null before performing an operation. This puts an additional burden on the programmer.

The intent of the null object pattern is to minimize null checking. Instead, we identify the null behaviour and encapsulate it in the type expected by the client code. We define null behaviour, or implement a very simple do-nothing method. This way we no longer need to deal with special handling of null references. This keeps our code clean and readable. A null object is very predictable and has no side effects because it does nothing.

To encapsulate a null object in the type expected by the client code, we create an abstract class specifying the various operations to be done. We then create concrete classes extending this class. One of these concrete classes will be a null object class providing appropriate do-nothing implementations. This class can be used seamlessly where we need to check for a null value.

As null objects should not have any state, we don’t need to create multiple identical null objects. This means we can implement null objects as singletons.

The null object pattern is a special case of the strategy pattern, i.e. a strategy of doing nothing.

The Null Object Method: AWT Example

The adapter classes in the java.awt.event package – ComponentAdapterContainerAdapterFocusAdapterKeyAdapterMouseAdapterMouseMotionAdapter and WindowAdapter – are not implementations of the Adapter pattern. They are actually Null Objects. It was a poor naming choice by Sun in the early days of Java.

If we implement a listener interface with more than one method in it, we are forced to define all of the methods in it, even if we’re just interested in listening for one event. The abstract XxxAdapter classes are convenience classes for creating listener objects. They define do-nothing/null methods for all of the defined interface methods, so we only have to override specific methods for the events we’re interested in.

The following code is the implementation of the KeyAdapter class (minus Javadoc comments):

package java.awt.event;

public abstract class KeyAdapter implements KeyListener {
   public void keyTyped(KeyEvent e) {}
   public void keyPressed(KeyEvent e) {}
   public void keyReleased(KeyEvent e) {}
}

We use the KeyListener and KeyAdapter classes as follows:

// empty text field 80 columns wide
TextField textField = new TextField(80);  

// Anonymous inner class using the KeyListener 
// interface to listen to the keys typed 
textField.addKeyListener(new KeyListener() {
      // only override the method we're interested in
      @Override public void keyPressed (KeyEvent e) {}
      @Override public void keyReleased(KeyEvent e) {}
      @Override public void keyTyped   (KeyEvent e) {
         // appropriate code
      }
   });

// Anonymous inner class using the KeyAdapter 
// class to listen to the keys typed.
textField.addKeyListener(new KeyAdapter() {
      // only override the method we're interested in
      @Override public void keyTyped (KeyEvent e) {
         // appropriate code
      }
   });

We can save writing a lot of boilerplate code when we use the adapter classes. The savings increase when we listen for other events:

  • The ComponentListener interface has 4 methods.
  • The MouseListener interface has 5 methods.
  • The WindowListener interface has 7 methods.

The MouseAdapter class implements 8 empty methods; it implements the MouseListenerMouseMotionListener and MouseWheelListener interfaces.

The WindowAdapter class implements 10 empty methods; it implements the WindowFocusListenerWindowListener and WindowStateListener interfaces.

Even though these adapter classes have all been marked as abstract, they are actually concrete classes, in that they contain only fully implemented code. They have been marked as abstract so we cannot instantiate an essentially null object using the new operator. We are forced to implement some code, even if it’s just an empty class code block:

textField.addKeyListener(new KeyAdapter() {} ); // works!
textField.addKeyListener(new KeyAdapter() );    // does not work!

As you can see, the null object is a simple and easy to use pattern, fulfilling a useful role.

The Optional Class

The java.util.Optional class provides a high-level solution for representing optional values instead of using null references. The Optional class is a very comprehensive implementation of the Null Object pattern with all the bells and whistles we can imagine. This will be a topic for a later tip.

What’s Next?

Next week we’ll dive into some of the factory patterns, starting with the (non-GoF) Simple Factory pattern. Stay tuned!

I’m always interested in your opinion, so please leave a comment. Your feedback helps me write tips that help you.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.