I was looking for a way to sort data in a JTable today and I very soon came upon this section in Sun's docs. TableSorter.java is so easy to use that all I had to do was literally this:
Voila. Took way longer to type this description than it did to actually do the work.
After that I changed the few lines of code as they describe. I ran it and tested it out, then I went back to figure out what I'd done. If you read the Sun documentation you'll get a lot of what I did. I also had the GoF (Design Patterns: Elements of Reusable Object-Oriented Software) next to me though. So I looked up the Decorator Pattern.
To paraphrase (I don't have it next to me now), the Decorator Pattern allows the developer to add functionality to a class without subclassing. Instead you write a sort of intermediary that exposes the same interface as the class you want to augment but with a couple extra features or methods.
As it applies to TableSorter and JTable, the TableSorter implements the TableModel and TableModelListener interfaces. That means that it has to support all the required public methods of those interfaces. For the most part, the TableSorter passes calls on to the underlying TableModel. Remember TableSorter doesn't contain the data itself, it's used to wrap another TableModel that does contain the data.
The extra features are visible in any call that passes in a row index. These are mapped to the value of the index according to the sorted order of the rows. How is the sorted order determined? That's where the extra setTableHeader() method comes in. By giving the TableSorter a reference to the table header, it's able to set up a listener that detects clicks on the header which trigger sorting of the entire table. Pretty slick, I thought.
I was so impressed by the TableSorter sample code because it's an elegant and useful class. It attaches it's functionality in a very clean way and serves as a good example of how the Decorator Pattern can be used to extend a class without the requirements of subclassing. The one thing I still have to test is whether the code that draws the sort order indicators will look right when colours or Look & Feel are changed.
The advantage of the Decorator Pattern in this case is that you can add on the features that the decorator gives you to any JTable. You could also layer multiple decorators one on top the other. That gives you the ability to reorder or remove the filtering applied to the JTable without changing any class heirarchy. It could even be done at runtime (for some fixed set of filters, of course).
Anyhow, I think there are quite a few similar decorators that could be written for tables. If you wanted to hide records that match or don't match a criterion, that could be done with a similar decorator. If you wanted to highlight an area that doesn't match cell boundaries (like a big circle around a few items), I think a decorator would be suitable. A custom Cell Renderer couldn't do it (I'd guess) if you were exceeding the bounds of a single cell. Perhaps data processing and validation when the data source for the table isn't the user. Basically anywhere you want to intercept data for the whole table, you can layer in another Decorator like the TableSorter. Pretty cool stuff. Then again, don't get carried away since there are lots of hooks in JTable for other things like TableModelListeners (which could handle recalculation of dependent cells, for example), and Custom Renderers for making cell contents look the way you want.
I guess I just love it when code is both elegant and useful.
[...] One thing I’ve been on about recently is Eclipse and Java development. So I thought maybe I could look at developing with J2EE and what kinds of interesting things I can build. I have a lot of goals: [...]