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

Take control with the Proxy design pattern

The Proxy design pattern substitutes a proxy for an object, making your apps more efficient

  • Print
  • Feedback

Page 6 of 6

Figure 3H shows the class diagram for the filter, which decorates a table model:

Figure 3H. Filter decorator class diagram. Click on thumbnail to view full-size image.

TableHighPriceFilter, by way of TableModelDecorator, implements the TableModel interface and forwards method calls to an enclosed table model instance -- the realModel. TableHighPriceFilter implements TableFilterDecorator, which is listed in Example 3H.

Note: The TableModelDecorator class is listed in "Decorate Your Java Code."

Example 3H. The abstract TableFilterDecorator class

import javax.swing.table.TableModel;
public abstract class TableFilterDecorator extends 
                                         TableModelDecorator {
   // Extensions of TableFilterDecorator must implement the
   // abstract filter method, in addition to tableChanged. The
   // latter is required because TableModelDecorator
   // implements the TableModelListener interface.
   abstract public void filter(int column);
   public TableFilterDecorator(TableModel realModel) {
      super(realModel);
   }
}


Example 4H lists the TableHighPriceFilter class:

Example 4H. The abstract TableFilterDecorator class

import javax.swing.table.TableModel;
import javax.swing.event.TableModelEvent;
public class TableHighPriceFilter extends TableFilterDecorator {
   // The lone constructor must be passed a reference to a
   // TableModel. This class decorates that model with additional
   // sorting functionality.
   public TableHighPriceFilter(TableModel model) {
      super(model);
      allocate();
   }
   // tableChanged is defined in TableModelListener, which
   // is implemented by TableFilterDecorator.
   public void tableChanged(TableModelEvent e) {
      allocate();   
   }
   // Three TableModel methods are overridden from
   // TableModelDecorator.
   public Object getValueAt(int row, int column) {
      return getRealModel().getValueAt(indexes[row], column);
   }
   public void setValueAt(Object aValue, int row, int column) {
      getRealModel().setValueAt(aValue, row, column);
   }
   public int getRowCount() {
      return rowCount == NOT_INITIALIZED ? 
                       getRealModel().getRowCount() : rowCount;
   }
   // The filter method filters out items that cost more than
   // one dollar.
   public void filter(int column) {
      int rowsNow = getRowCount();
      int[] newIndexes = new int[rowsNow];
      int newRowCount = rowsNow;
      for(int i=0, j=0; i < rowsNow && j < rowsNow;) {
         String price = (String)getRealModel().
                                getValueAt(indexes[j], column);
         if(price.startsWith("$."))    { // less than a dollar
            newIndexes[i++] = indexes[j++];
         }
         else {
            newRowCount--;
            ++j;
            continue;
         }
      }
      rowCount = newRowCount;
      for(int i=0; i < rowCount; ++i)
         indexes[i] = newIndexes[i];
   }
   private void allocate() {
      indexes = new int[getRowCount()];
      for(int i=0; i < indexes.length; ++i) {
         indexes[i] = i;         
      }
   }
   private int indexes[];
   private static int NOT_INITIALIZED = -1;
   private int rowCount = NOT_INITIALIZED;
}


The TableHighPriceFilter class inherits forwarding methods -- which forward to the actual model -- from TableModelDecorator. For some decorators, forwarding methods can constitute a good deal of code, so it's convenient to encapsulate those methods in a base class for other decorators to extend.

Email

Thanks for all the email you've sent in response to the first two Java Design Patterns installments. I've had some interesting discussions about design patterns and object-oriented (OO) software development. Here's one such exchange that points out the differences between object composition and delegation, and why the Decorator pattern uses the former but not the latter:

Tom Palmer wrote:

Decorators are a form of dynamic inheritance system, but with normal OO inheritance, no matter where a method is implemented in a hierarchy, this always refers to the same object. With normal decorators, however, once a call is passed on, the wrapped object doesn't know about the original object. It's as if the super method call forgot who this was.

There's an almost convenient mechanism for passing the this reference: two versions of each method, one with an extra parameter representing the effective this, which I call the target. The short form of each method just calls the expanded form with the current this as the target. Automatic design patterns via proxies can be made to look for expanded methods and pass in the proper target object.



Palmer makes a good point. Instead of comparing decorators to inheritance, it's more appropriate to compare the more general composition or delegation techniques (which he describes above) to inheritance.

Decorators use object composition by forwarding method calls to an enclosed object. It's called composition because the enclosed object cannot access its enclosing object (the this reference he discusses above).

Delegation is just like composition, except the enclosing object passes a reference to itself to the enclosed instance. There are several ways for the enclosing object to make itself known to the enclosed object -- what Palmer describes above is one way.

For the Decorator pattern, you use composition instead of delegation, because delegation requires the enclosed object to be aware of its enclosing object. One of the Decorator pattern's main attractions is that enclosed objects (and the objects that use the decorators) are oblivious to decorators. For example, in one example discussed in "Decorate Your Java Code," table models remain unaware of the sorters that decorate them, so that any table model can be sorted.

About the author

David Geary is the author of Advanced JavaServer Pages (Prentice Hall, 2001; ISBN: 0130307041) and the Graphic Java series (Sun Microsystems Press). David has been developing object-oriented software in numerous object-oriented languages for 17 years. Since the Gang of Four's Design Patterns book was published in 1994, David has been an active proponent of design patterns, and has used and implemented design patterns in Smalltalk, C++, and Java. In 1997, David began working full-time as an author and occasional speaker and consultant. David is a member of the expert groups defining the JSP (JavaServer Pages) standard custom tag library and JavaServer Faces, and is a contributor to the Apache Struts JSP framework.

Read more about Core Java in JavaWorld's Core Java section.

  • Print
  • Feedback

Resources