To demonstrate the design, we'll implement a progress bar widget with several configuration parameters and/or properties.
The Progress component supports:
Traditionally, there are two ways to communicate initialization data to an instance:
There is no suggestion here to limit access methods. Access methods are a basic design component for object-oriented programming. In the case of instance creation, however, post-hoc initialization can be cumbersome. For this reason, it's common to provide a variety of constructors.
Of course, it's possible to provide one monster constructor with a parameter for each configuration option. In general, providing
this type of reference constructor is a good idea. Given the definition of a reference constructor, other convenience constructors with fewer parameters can then invoke the reference constructor by calling this() and filling in default values:
public Progress(int width, int height, int margin,
Orientation orientation, DisplayPercent display_percent,
Color bg, Color fg, Color text) {
...
} /* Progress */
public Progress(int width, int height, Color fg) {
this(width, height, DEFAULT_MARGIN,
new Orientation(), new DisplayPercent(),
null, fg, DEFAULT_TEXT);
} /* Progress */
With eight configurations options, however, the number of convenience constructors necessary to support common configuration scenarios is large. The issue is not the difficulty in coding the constructors, but the difficulty, for the user, in having continually to refer to the API to pick one of many constructors with varying signatures.
One solution is to provide a supporting configuration class for each primary class that requires an unwieldy number of configuration
options. For example, the Progress widget is accompanied by ConfigureProgress. The basic idea is to first create a nongraphical class with a public instance variable for each configuration option, and
then provide a constructor for the primary class that takes a configuration instance as an argument:
public final class ConfigureProgress {
public int width, height, margin;
public Orientation orientation;
public DisplayPercent display_percent;
public Color bg, fg, text;
ConfigureProgress()
{
width = Progress.DEFAULT_WIDTH;
height = Progress.DEFAULT_HEIGHT;
margin = Progress.DEFAULT_MARGIN;
orientation = new Orientation();
display_percent = new DisplayPercent();
bg = null;
fg = null;
text = Progress.DEFAULT_TEXT;
} /* ConfigureProgress */
} /* ConfigureProgress class */
Progress for each configuration option.Then, the Progress component provides a constructor with a single parameter representing an instance of ConfigureProgress:
public Progress(ConfigureProgress cp) {
this(cp.width, cp.height, cp.margin,
cp.orientation, cp.display_percent,
cp.bg, cp.fg, cp.text);
} /* Progress */
Last, when instantiating a Progress widget, a programmer can modify the relevant configuration options directly in the ConfigureProgress instance before passing it to the constructor for Progress:
ConfigureProgress cp = new ConfigureProgress();
cp.width = 40;
cp.height = 150;
cp.bg = Color.red;
cp.fg = Color.cyan;
p4 = new Progress(cp);
In this case, the programmer has to know the names of eight instance variables, but doesn't have to remember or look up a large number of constructor signatures.
This type of pairing of primary and secondary configuration classes is not generally recommended because, in most cases, the set of constructors for a class is small. Only when the set of constructors becomes cumbersome does the additional complication of having a secondary configuration class becomes a better alternative.
Minimally, to test Progress's display operations, four instances are necessary -- one for each orrientation. The test applet, ProgressMultiTest, instantiates four progress bar instances and "drives" them from separate threads of execution:

If you have a JDK 1.1-compatible browser, you can run the ProgressMultiTest applet directly. (This applet is accompanied by several descriptive paragraphs, so you must scroll down to find the applet on its HTML page.)
The Progress component is primarily an "internal" widget. That is, Progress, like AWT's Label component, does not provide a three-dimensional look and feel. It is primarily designed for display within areas that are
strictly controlled by the parent (container), for example, the area where the progress bar appears at the bottom of a Web
browser.
The Progress component extends Panel in order to take advantage of the insets capability for containers. Progress manages a Canvas-derived drawing area as its only child. Thus, the margin area is easily implemented by controlling the insets values for
the enclosing panel.
Normally, a Progress instance is configured with no margin, for example, when located at the bottom of a browser's main window. In these circumstances
it's common to set the Progress component's background color to match that of its container, like the second progress widget in the previous screenshot.
With this brief example, you should see the value of providing a secondary class to configure initialization parameters when the quantity of class properties is relatively large. Without the secondary class, you would need to design a cumbersome set of constructors, making the API for your class more complex. The resulting design with the secondary class should be more maintainable in the long-run and simpler for the user of your classes.
Note to our readers: Have you come up with any Java tips and tricks you think may be of value to your fellow JavaWorld readers? If so, send them to javatips@javaworld.com, and you may see your name "in lights" as the author of a future Java Tip!