Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Decorate your Java code

A look at the Decorator design pattern

  • Print
  • Feedback
Being somewhat of a closet Luddite, I only recently purchased my first cell phone. My phone is faceplate-ready -- in other words, I can snap on a stylish faceplate. As far as I can tell, faceplates are the only dynamically changeable aspect of my cell phone. For example, I cannot snap on antennas or speakers; those are set statically at the factory.

Software decorators, like cell phone faceplates, encapsulate some functionality that you can snap onto an existing object; for example, here's a code fragment that snaps sorting onto an existing Swing table model:

TableSortDecorator sortDecorator = new TableSortDecorator(table.getModel());
table.setModel(sortDecorator);


The preceding code swaps out a table's model for a decorator. After the swap, whenever the table accesses its model, it unknowingly accesses the sort decorator. The decorator adds sorting capabilities to the model it decorates, and delegates other functionality to the real model.

Like cell phones, software heavily reliant on inheritance includes a high percentage of statically defined objects. Just as a cell phone's antenna or speaker is statically defined at the factory, base classes and their extensions are statically defined at compile time. Because inheritance is static, it does not allow you to swap out an aspect of an object's behavior at runtime (such as the table model decorator in the code fragment above). Because you can use decorators much like Legos to snap together an object with desired behaviors at runtime, the Decorator design pattern proves far more flexible than inheritance.

In this article, I first introduce the Decorator pattern, starting with an example that shows how to use Java's I/O decorators. I then outline the Decorator pattern's statics and dynamics with UML class and sequence diagrams, respectively. I conclude with an example decorator that, as alluded to above, adds sorting to Swing tables.

Note: In the first installment of this column -- "Amaze Your Developer Friends with Design Patterns" -- I introduced Decorator, among other patterns. You may wish to read that introduction before proceeding with this more detailed look.

The Decorator pattern demystified

Decorator: Attaches responsibilities to objects at runtime. Decorators prove more flexible than inheritance, which attaches responsibilities to classes at compile time.

In "Amaze Your Developer Friends with Design Patterns," I described input streams and the Decorator pattern. Example 1 from that article demonstrates instantiating a line number reader:

Example 1. Instantiating I/O decorators

1. FileReader       frdr = new FileReader(filename);
2. LineNumberReader lrdr = new LineNumberReader(frdr);


The preceding code creates a reader -- lrdr -- that reads from a file and tracks line numbers. Line 1 creates a file reader (frdr), and line 2 adds line-number tracking.

At runtime, decorators forward method calls to the objects they decorate. For example, in the code above, the line number reader, lrdr, forwards method calls to the file reader, frdr. Decorators add functionality either before or after forwarding to the object they decorate; for example, our line number reader tracks the current line number as it reads from an input stream.

  • Print
  • Feedback

Resources