Phased Process decouples sequential operations and provides a flexible dispatch mechanism In situations where a set of operations must proceed in an orderly fashion, you have at your disposal several tried-and-true solutions. The inexperienced programmer might code each operation so that it calls the next operation, similar to a one-way linked list. While this approach works, it is brittle because it requires each operation to know about the next.Alternatively, depending on the problem being solved, you might apply the State pattern, as described in Design Patterns. The State pattern tailors to objects that must alter their own behavior when their internal state changes. However, when you have an object controlling other, separate objects and want to keep them loosely coupled yet allow them to transfer control to one another, you need a different solution. One battle-tested pattern that addresses these requirements is the Phased Process pattern.The Phased Process pattern is especially useful because it: Decouples sequential operationsUnifies the API for phased processesProvides a flexible dispatch mechanismAnd that’s what you’ll learn more about in this article.Process in phasesWe’ve all seen installation wizards, those programs that progressively walk you through license acceptance, option selection, and so on before finally installing software on your computer. This is a great example of a phased process: each dialog box in the wizard represents one phase of the installation process.The Phased Process pattern uses a dispatching mechanism that knows about all the phases and executes them successively. Because the logic for transition between phases is concentrated in the dispatcher, each phase is required to know little, if anything, about any other phase. This modularity is especially nice when, as so often happens in development, the application design changes and you must modify the number or order of phases. Further, with this pattern, you can simply insert logic at transition points and provide more advanced mechanisms for navigating through a phase set. For example, providing a Previous button so the user can revisit the last executed phase is a trivial exercise, as is providing a Finish button that completes the process by using default values.Motivation behind the patternPhased Process differs from the State pattern in that it controls ordered execution of disparate classes, rather than simply changing its own behavior when its state changes. Phased Process is narrower in scope and targeted at precisely those operation types discussed above: sequential synchronous processes.This pattern is motivated by the need for a consistent and workable solution to problems that require successive operation of disparate objects. Phased Process provides a uniform API for execution and transition of ordered process phases. Robust implementations allow out-of-order processing, backwards motion through phases, complete cancellation with no side effects, and early successful termination. The key notion is that you can change the phase, or operation state, through a uniform transition mechanism. The execution of the current phase is likewise presented in a uniform manner. Concentrating phase transition logic into one class increases clarity, illustrates intention, and reduces maintenance.When to use itYou might apply the Phased Process pattern when a series of synchronous operations must be performed and you want to isolate those operations from each other, perhaps to simplify reordering operations or the later integration of new operations. Typical examples include game leveling, where completing one game phase moves you to the next; those ubiquitous installation wizards; and escalating the severity of user alerts from beeps to double beeps, and from status-bar notes to modal alert messages.This pattern’s benefits flow from how it partitions each phase’s behavior and knowledge from the behavior and knowledge of all other phases. The deliberate and explicit concentration of transition logic and the simple and direct API addressing the fundamental aspects of phased process operation are also key benefits. These do not come at the price of flexibility, which, as you’ll see, is built into the framework presented here. A simple implementationSeveral variants of this design are possible. The simplest variant — as Figure 1’s FontPicker application demonstrates — ratchets through an ordered set of phases. FontPicker’s user interface (UI) is fairly irritating; few developers would choose to force their users through several dialogs just to specify a font. However, it does illustrate a simple phased process very well.When you run the FontPicker program (see Resources to download the source code for all sample programs in this article), notice the buttons that let you step through the phases: Previous and Next.Also notice the Cancel button, which halts the process without side effects. Clearly, this UI is only useful in situations where the user must step through each and every phase or cancel the operation completely. A more complex program I’ll present later uses a more useful framework: it implements Finish and Previous buttons. However, to illustrate a simple phased process, the FontPicker program’s one-way incremental approach shows the fundamental control structure and is the basis for more elaborate implementations.The heart of this phased process resides in the FontSelectProcess class, and the heart of that class is the performCurrentPhase() method: public void performCurrentPhase() { switch (<b>currentPhase</b>) { case PHASE_LOAD_ALL_FONTS: // ... housekeeping code omitted ... break; case PHASE_PICK_FONT: showNewFrame(new PickFont(this, parameters)); break; case PHASE_COLOR: showNewFrame(new PickColor(this, parameters)); break; case PHASE_STYLE: showNewFrame(new PickStyle(this, parameters)); break; case PHASE_SIZE: showNewFrame(new PickSize(this, parameters)); break; default: System.out.println("Error: performCurrentPhase: Unknown phase: " + currentPhase); } } Even if you haven’t run the program, you can tell at a glance what phases are available and the order in which they’re likely to occur. Changing the execution order is a simple operation; you only need to change the code in one class. Likewise, adding or removing phases is straightforward. You can factor much of a phased-process handler’s mechanics into a generic class, making implementing new processes a breeze. FontSelectProcess extends SimpleProcess, which provides some convenience methods — most important, one that handles phase transitions. It does this using a simple, sleek, and very flexible method called phasedProcessHandler(): public void phasedProcessHandler(int msg) { switch(msg) { case MSG_INIT: <b>currentPhase</b> = 0; break; case MSG_NEXT: <b>currentPhase++</b>; if (numberOfPhases <= currentPhase) { // all phases have executed processFinished(); return; } break; case MSG_PREV: if (0 < currentPhase) { <b>currentPhase--</b>; } else { System.out.println("Hey - don't let user go" + "back beyond first phase!"); } break; case MSG_CANCEL: // bail out of the process - return here so we // don't execute performCurrentPhase processCancelled(); return; // <-- note: return default: System.out.println("Error: advanceCurStage: Unknown msg: " + msg); break; // default } <b>performCurrentPhase();</b> } You use the currentPhase variable to track which phase is currently executing. On phase transitions, this value is modified to reflect the new phase. The phasedProcessHandler() method sets currentPhase to the next executed phase. Since my phases are numbered sequentially from zero upwards, I can simply increment or decrement currentPhase to move forward or backward one step. Finally, the code calls performCurrentPhase(), a method that in the font-picking subclass executes the desired phase.Who calls the phasedProcessHandler()? In general, the user does, by pressing the Next, Previous, or Cancel buttons provided by each dialog’s UI. Since these controls are ubiquitous, you can use subclassing to your advantage and wrap up the UI in one place. In this case, all interface dialogs are built from an abstract class called SimpleFrame, an extension of the JInternalFrame class. SimpleFrame provides the common interface components and logic for interacting with SimpleProcess.When the user presses the Next button, SimpleFrame automatically executes this method: protected void nextPressed() { if ( ! validateData() ) return; saveData(); setVisible(false); dispatcher.phasedProcessHandler(SimpleProcess.MSG_NEXT); } SimpleFrame provides a simple data validation framework useful in contexts where the user can enter invalid values. While this is over-engineered for this particular program, it is worthwhile to consider that future enhancements will likely require some sort of validation. Having an integrated, uniform approach for data validation is worth the extra effort. As you can see, the nextPressed() method calls validateData(), another method in SimpleFrame. The abstract implementation simply returns true, though subclassers will generally extract the user’s entries from the UI and test those values for validity. If any data is invalid, the program should inform the user (possibly by using a convenience SimpleFrame method called badDataAlert()) and return false to the caller. Should the data be invalid, the nextPressed() method prevents the next phase from executing, letting the user correct the data or cancel. If the data is deemed valid, saveData() is called, allowing subclasses to properly store the data. The Lissajou program’s implementation provides a fleshed-out example of the validation framework in action.Flexible phasesGenerally, phased UI processes are simple, sequential affairs; one step leads to the next and, if you’re feeling generous, you let the user go backwards, cancel, or jump to the end. However, you may run into situations that require skipping or branching among different phases.The Lissajou demo program (named for nineteenth-century French physicist Jules Antoine Lissajou, who discovered the looping curves our application renders) shows skipping in action. Skipping among phases is pretty simple. It’s tricky only when the user presses the Previous button. You can either decrement the current phase number, taking the user to something she’s already indicated she wants to skip, or you can remember her path through the phases and go back to the last phase she saw. The latter solution proves more elegant and intuitive. You implement this breadcrumb trail with a stack that tracks the user’s route; and then, voilà! Going backwards is as easy as going forwards. Here are the LissajouDispatcher class’s essential guts: public void performCurrentPhase(Object data) { switch (currentPhase) { case LISSPHASE_EQUATION: startPhase(new LissajouEquation(this, parameters)); currentPhaseFrame.firstFrameUI(); // remove Previous button break; case LISSPHASE_COLOR: startPhase(new LissajouColors(this, parameters)); break; case LISSPHASE_LINE: startPhase(new LissajouLine(this, parameters)); currentPhaseFrame.finalFrameUI(); // remove Next button break; default: break; } } Figure 2 shows the dialog that the LISSPHASE_EQUATION phase displays.Notice the Skip to Lines button during the LISSPHASE_EQUATION phase. By pressing this button, you skip over LISSPHASE_COLOR and go straight to LISSPHASE_LINE. Along the way, support code has recorded the previous currentPhase value and pushed it on a stack. If you then press the Previous button, you automatically go back to LISSPHASE_EQUATION without going through LISSPHASE_COLOR. I distilled the mechanics for handling this and other housekeeping chores in a class called PhasedProcess, which contains a slightly more complex phase-process handler than you saw in the FontPicker example: public void phasedProcessHandler(int msg, Object data) { switch(msg) { case MSG_INIT: // set currentPhase to data value if passed, or set to zero if (null != data && data instanceof Integer) { currentPhase = ((Integer)data).intValue(); } else { currentPhase = 0; } // push stage onto stack so next frame's Previous button works frameStack.add(new Integer(currentPhase)); break; case MSG_NEXT: currentPhase++; break; case MSG_PREV: if (frameStack.size() == 1) { System.out.println("Error: Popped too much off the stack!"); break; } // grab previous frame id from the stack Integer prevPhase = (Integer)frameStack.get(frameStack.size() - 2); frameStack.remove(frameStack.size() - 1); // remove frame we just came from frameStack.remove(frameStack.size() - 1); // remove frame we are going to currentPhase = prevPhase.intValue(); break; case MSG_SKIP: if (null != data && data instanceof Integer) { currentPhase = ((Integer)data).intValue(); } else { System.out.println("Error: phasedProcessHandler" + " got MSG_SKIP with bad phase parameter."); } break; case MSG_FINISH: processFinished(); break; case MSG_CANCEL: processCancelled(); break; default: System.out.println("Error: phasedProcessHandler: Unknown msg: " + msg); break; // default } // switch(msg) // go do it performCurrentPhase(data); } The additional features, skipping and maintaining a stack of traversed phases, are handled here. The dialog’s ancestor, PhaseFrame, is identical to the one used in the FontPicker example with the notable addition of a skipping method (used by the Skip to Lines button in the Lissajou example): public void skipToPhase(int newPhase) { dispatcher.phasedProcessHandler(PhasedProcess.MSG_SKIP, new Integer(newPhase)); } Following along, you can see that the skipToPhase() method calls phasedProcessHandler() with the value of the phase to skip to. This proves one point: the dialog must know about other phases, something you should try to avoid. To that end, you could further abstract this knowledge, the constant value that identifies a particular phase, to keep things loosely coupled. The Lissajou example also uses data validation. Whenever the user presses the Next or Finish buttons, validateData() is called, which retrieves the user’s data from the UI and examines it. If there’s a value error, validateData() uses the badDataAlert() method to inform the user of the problem, and it then returns false, preventing the phase from proceeding. protected boolean validateData() { JTextField theField = null; // used for error reporting try { theField = txt_v1; v1 = Float.parseFloat(theField.getText()); theField = txt_v2; v2 = Float.parseFloat(theField.getText()); } catch(NumberFormatException ex) { theField.requestFocus(); theField.setCaretPosition(0); theField.moveCaretPosition(theField.getText().length()); badDataAlert( theField.getText() + " is not valid real number.nPlease re-enter."); <b>return false</b>; } <b>return true;</b> } // validateData Another method, saveData(), will write the data if the validateData() method permits: protected void saveData() { parameters.v1 = v1; parameters.v2 = v2; parameters.rotationSpeed = MAX_SPIN_SPEED - slid_spin_speed.getValue(); } // saveData You could certainly combine the operations of validateData() and saveData(). For example, validateData() could also save the data, though that would muddy validateData()‘s intention. saveData() could validate the data, perhaps throwing an Exception should validation fail. However, for readability and maintainability, you’re better off breaking this functionality into separate and distinct operations. You now have at your disposal a pattern and framework for handling sequential operations with flexibility and ease. You can choose to use either the SimpleProcess class or the PhasedProcess class as your starting point. While here we effectively used a base class for the UI frames, you could certainly use completely unrelated classes to implement any or all phases; there is no stricture on what you execute in a phase.The real worldPhased processes occur on a broad spectrum in many different guises. Having an adaptable set of tools to address their wide variety lets you gracefully and quickly address the problem at hand. In addition to providing elegance, these tools help ensure that code is maintainable in the long term. You will find this pattern a useful weapon in your programming arsenal. To extend the framework, read the sidebar below, “Extend Lissajou.”Jon Benton has been developing software in numerous languages for more than 20 years. He spent 12 of those years as a developer at DTRO Software, Inc., specializing in forecasting and inventory control. Five more years he spent in residence at Presage Studios and working as an independent contractor writing computer game software. Currently, he is a senior developer with Torus Technologies, writing software for robotic observatories. Design PatternsJava