Wizard API updated!
Tim Boudreau has released a new version of the Swing Wizard library (version 0.997) that fixes the WizardException bug reported in JavaWorld's recent Open Source Java Project profile. The article's examples have been reworked to test out the new, improved WizardException. Thanks, Tim, for this helpful fix!
Open Source Java Projects: The Wizard API

Newsletter sign-up

Sign up for our technology specific newsletters.

Enterprise Java
View all newsletters

Email Address:

Java Tip 75: Use nested classes for better organization

Express coupling between components in Java subsystems with top-level nested classes

A typical subsystem in a Java application consists of a set of collaborating classes and interfaces, each performing a specific role. Some of these classes and interfaces are meaningful only in the context of other classes or interfaces.

Designing context-dependent classes as top-level nested classes (nested classes, for short) enclosed by the context-serving class makes this dependency clearer. Furthermore, the use of nested classes makes the collaboration easier to recognize, avoids namespace pollution, and reduces the number of source files.

(The complete source code for this tip can be downloaded in zip format from the Resources section.)

Nested classes vs. inner classes

Nested classes are simply static inner classes. The difference between nested classes and inner classes is the same as the difference between static and nonstatic members of a class: nested classes are associated with the enclosing class itself, whereas inner classes are associated with an object of the enclosing class.

Because of this, inner class objects require an object of the enclosing class, while nested class objects do not. Nested classes, therefore, behave just like top-level classes, using the enclosing class to provide a package-like organization. In addition, nested classes have access to all members of the enclosing class.

Motivation

Consider a typical Java subsystem, for example a Swing component, using the Model-View-Controller (MVC) design pattern. Event objects encapsulate change notifications from the model. Views register interest in various events by adding listeners to the underlying model of the component. The model notifies its viewers of changes in its own state by delivering these event objects to its registered listeners. Often, these listener and event types are specific to the model type, and therefore make sense only in the context of the model type. Because each of these listener and event types must be publicly accessible, each must be in its own source file. In this situation, unless some coding convention is used, the coupling between these types is difficult to recognize. Of course, one may use a separate package for each group to show the coupling, but this results in a large number of packages.

If we implement listener and event types as nested types of the model interface, we make the coupling obvious. We can use any access modifier desired with these nested types, including public. In addition, as nested types use the enclosing interface as a namespace, the rest of the system refers to them as <Enclosing>.<Nested>, avoiding namespace pollution inside that package. The source file for the model interface has all the supporting types, which makes development and maintenance easier.

Before: An example without nested classes

As an example, we develop a simple component, Slate, whose task is to draw shapes. Just like Swing components, we use the MVC design pattern. The model, SlateModel, serves as a repository for shapes. SlateModelListeners subscribe to the changes in the model. The model notifies its listeners by sending events of type SlateModelEvent. In this example, we need three source files, one for each class:

1 | 2 | 3 |  Next >
Resources