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

Solve the date-selection problem once and for all

Implement a date-selection widget using the Decorator pattern

  • Print
  • Feedback

Date selection is a problem that pops up every few months when you build client-side graphical user interfaces (GUIs). Unfortunately, Java doesn't provide anything like a DateChooser class, and the date-selection widgets I found in a recent Web search were too heavyweight for my purposes. I wanted something clean, unobtrusive, and flexible. Figure 1 shows a few variants of this article's class, so you can see what I mean by "clean" at the display level.

Figure 1. Various ways to present a Date_selector object



The free off-the-Web solutions were great examples of the you-get-what-you-pay-for principle: amateurish code that must be completely rewritten to be useful. This article's example, in fact, started out as an off-the-Web control, but by the time I finished fixing it, not a single line of the original code remained, and the architecture had completely changed (or, I should say, I added an architecture to an amorphous Java mass). So much for "free."

My widget also provides a good Decorator design pattern demonstration and a good look at Java's Calendar class, and it shows how to implement your own title bars and frames on a Swing JDialog.

Decorators

As is the case with any complex problem, the solution is greatly simplified by breaking the big problem up into smaller problems, each of which can be easily implemented (and tested). The Decorator pattern is great for this approach.

You've seen decorators if you've used Java's input/output (I/O) classes. The complex problem is efficiently reading a compressed stream of bytes, for example. You can do this with one massive class, but it's easier to break the problem up into three distinct subproblems:

  1. Read bytes
  2. Make reads more efficient with buffering
  3. Decompress a stream of bytes


Java solves the first problem with a FileInputStream, instantiated like this:

    try
    {   InputStream in = new FileInputStream( "file.name" );
    }
    catch( IOException e )
    {   System.err.println( "Couldn't open file.name" );
        e.printStackTrace();
    }


You then add buffering with a decoration (or "wrapping") strategy. You wrap the InputStream object with another InputStream implementor that buffers bytes. You ask the wrapper for a byte; it asks the wrapped stream for many bytes and returns the first one. The decorator wrapping goes like this:

    try
    {   InputStream in = new FileInputStream( "file.name" );
        in = new BufferedInputStream( in );
    }
    catch( IOException e )
    {   System.err.println( "Couldn't open file.name" );
        e.printStackTrace();
    }


Add decompression with another decorator:

    try
    {   InputStream in = new FileInputStream( "file.name" );
        in = new BufferedInputStream( in );
        in = new GZipInputStream( in );
    }
    catch( IOException e )
    {   System.err.println( "Couldn't open file.name" );
        e.printStackTrace();
    }


You can increase filtering by adding more decorators.

This solution is very flexible. You can mix and max the decorators to get the feature mix you need. More importantly, each decorator is relatively simple because it solves only one problem. Consequently, the decorators are easy to write, debug, and modify without affecting the rest of the system. I can change the buffering algorithm by rewriting BufferedInputStream, for example, and not touch any other decorators (or any code that uses them). I can also add new filter functionality simply by implementing a new decorator. (Classes like CipherInputStream were added to Java this way.)

  • Print
  • Feedback

Resources