HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

In this month's column I'm going to show you how to use Java 1.1's new "inner classes" to control a windowed UI. The big advantage I've found to using this technique is that it makes creating and initializing a Java user interface simple, the technique is easy to understand and it centralizes non-reusable code (instead of spreading it across multiple classes).

I've found this technique useful in a couple of different projects, so hopefully you will find it useful, too. The first thing I'd like to convince you of is the viability and simplicity of the "Model/View/Controller" design pattern for building UIs. The idea behind this pattern is that you can de-couple UI classes from reusable application classes and separate both from non-reusable application classes.

You build an MVC interface by separating the application functionality from user-interface functionality. For my example, I'm going to pretend I have an image composition application (call it IComp) that I'm trying to build. IComp allows users to load images from files and apply image filters to them.

The core of IComp, as is the case with most windowed applications, is a set of application classes that can do the "under the table" stuff that applications need to get done. For example, I might design IComp to have a generic ImageFilter class:

// Public interface of ImageFilter
public class ImageFilter {
Image applyFilter(Image src);
Property getProperties();
void setProperty(String name,
String newValue);
}

I might also like a way to store images into a file, which I could do using an ImagePersistor class:

// Public interface of ImagePersistor
public class ImagePersistor {
void init(String storageName)
throws IOException;
void close();
void storeImage(String name, Image in)
throws IOException ;
Image retrieveImage(String name)
throws IOException;
}

Both the ImageFilter and ImagePersistor classes are examples of reusable application classes. These are like vertical-market classes: classes that I would probably want to reuse in different image-processing applications.

To build the UI of the IComp application I want to reuse as many existing UI classes as possible. For example, I might want to use some of the java.awt package classes (Button, Canvas, etc.). I might also want to use some more powerful, third-party Java interface classes (a hierarchical tree control, an Image displayer, a color chooser, etc.).

Again, this second group of classes is going to be reusable. I might want to use them in multiple different applications I build. In the cases of both the application classes and interface classes I want to ensure reusability as much as possible. (Remember: Reuse means improved maintainability and faster development. These are very good things.)

The "Model/View/Controller" design pattern attempts to break down application code into three distinct types of classes: those that encode a Model, those that encode a View of the Model and a Controller that manipulates both the Model and the View. In the IComp application I've been making up, the application classes are the Model. They define the state of something that is to be displayed and associated utility classes. The interface classes would be like the View. They display the Model to the user.

What's great about MVC is that it allows us to ensure the reusability of both the Model and View classes. What we've done by splitting up the application and interface classes is decoupled them from each other. I don't need to have the application classes to compile my interface classes, and I don't need my interface classes to compile my application classes. In fact, we can envision that I could use a completely different set of UI classes to build my IComp interface, but I would not have to change (or even re-compile) my application classes. That's good flexibility and proves reusability.

What's missing, however, is any code that actually makes a working application. Sure, I have interfaces classes I know I'm going to use and I have application classes I know my IComp application is going to use, but I don't actually have anything that "glues" them together. That's what MVC's "Controller" concept is for. The Controller is the piece that reacts to user input by manipulating the Model (like when the user presses some "Apply Filter" button in IComp's UI), or changes the View (like when the user moves one of the scrollbars attached to the view of a filtered image in IComp).

The controller classes are always going to be coupled to the Model and View classes. (Those purist readers who like to argue can grumble at the word "always" in the previous sentence, but it is a close enough approximation of the truth to get the idea across.) The job of the Controller classes is to "listen" to events in the UI and react to them by calling methods in the application or view objects. In order to compile my controller ("listener" and "actor") classes, those classes need to know about the events and methods available in both the application and interface classes.

This coupling of the Controller to the Model and View classes means that usually the reusability of Controller classes is minimized. For example, I need to make a special listener in IComp that listens for the "Apply Filter" button to be hit by the user, and to actually call the applyFilter() method of a specific ImageFilter object. So, I'm not going to reuse the same listener class in another version of IComp that doesn't have an "Apply Filter" button. So, reusability is minimal.

Java 1.1 provides us with a new tool called "anonymous inner classes" that is great to use for the role imagined by the Controller concept. Anonymous inner classes are, by their very nature, not very reusable. However, they are very easy to create. Listing 1 defines a Controller class I might make for my IComp application. The Controller object itself is responsible for listening to events that happen in the interface and reacting to those events by calling methods in any ImageFilters or UI objects that need to be manipulated. I achieve this functionality by filling the Controller class with a series of anonymous inner class objects, each one responsible for reacting to a particular user event.

Of course the Controller class probably is not reusable in other applications. In a very real sense the Controller class is the application. Its main() method constructs the ImageFilters (Model objects) and the UI objects (View objects) as well as a series of anonymous inner class objects to listen to and react to user events (Controller objects). What else is it an application does other than:

  • Build a UI?
  • Build the objects the UI is presenting an interface to?
  • React to user input by manipulating the UI and/or application objects?
I generally find that I have some stable of UI classes (JFCs, third-party packages, etc.). These classes are going be used in any of my Java applications (or applets). For a particular series of applications or applets that deal with a particular problem domain I develop a series of domain-specific classes (e.g., IComp's ImageFilter or ImagePersistor classes might be used in any imaging application, but probably wouldn't be used in, say, the accounting or financials arena). For each individual application or applet, I end up with very few application-specific (non-reusable) classes such as the Controller class in Listing 1.

This setup, I find, maximizes the reusability of my classes without compromising code simplicity. The MVC design pattern helps me to organize, design and debug my code in many different development environments - whether I'm using the JDK or any one of the many Java development environments out there. The design is very flexible, stable and quite scalable.

About the Author
Brian Maso is a programming consultant working in California. He is the co-author of The Waite Group Press's, "The Java API SuperBible." Before Java, he spent five years corralled in the MS Windows branch of programming, working for such notables as the Hearst Corp., first DataBank, and Intel. Readers are encouraged to contact Brian via e-mail with any comments or questions at [email protected]

	

Listing 1:
 
A simple Controller class with a main() method that creates application objects 
and “glues” them together with several anonymous inner class objects.
 
import java.awt.*; 
import java.awt.event.*; 
public class Controller { 
 private static ImageFilter m_filter; 
 private static Image m_image; 
 private static Frame m_ui; 

 public static void main( 
   String[] args) { 
  // Create main frame window, hook up 
  // listener for WINDOW_CLOSING events 
  m_ui = new Frame("IComp Application"); 
  WindowListener wl = new WindowAdapter() { 
   public void windowClosing(WindowEvent we) { 
    System.exit(-1); 
   } 
  } 
  m_ui.addWindowListener(wl); 

  // Add "Apply Filter" button to UI, and 
  // add listener. 
  Button buttonApplyFilter = 
    new Button("Applet Filter"); 
  ActionListener al = new ActionListener { 
   public void actionPerformed(ActionEvent ae) { 
    m_filter.applyFilter(m_image); 
   } 
  } 
  m_ui.add(buttonApplyFilter); 
  buttonApplyFilter.addActinoListener(al); 

  // ...Build interface of UI objects, and 
  // anonymous inner class listeners to react to 
  // user events... 

  // Finally, show the interface. 
  m_ui.setVisible(true); 
 } 
}


 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.