I'm developing a MVC Java Swing application, which will offer the user at least a dozen of different actions. Some of these actions will trigger execution of a SwingWorker object, while others are pretty simple (or common). I started with the approach discussed here, but I modified it in order to avoid to define an implementation of the AbstractAction class for any "common" action. This is the solution I implemented:
The Action enum class defines my "common" actions:
public enum Action {
// label mnemonic modelObject modelMethod
EXIT ("Exit" , KeyEvent.VK_E , "SubModel", "openExitView")
,FLAG_1 ("Flag 1" , KeyEvent.VK_1 , "Options", "setFlag_1")
,FLAG_2 ("Flag 2" , KeyEvent.VK_2 , "Options", "setFlag_2")
,HELP ("Help" , KeyEvent.VK_L , "SubModel", "openHelpView")
,ABOUT ("About" , KeyEvent.VK_A , "SubModel", "openAboutView");
Then, in the Controller class, I added this method:
public AbstractAction getAction(final Action action) {
AbstractAction actionImpl = new AbstractAction(action.label) {
{
putValue(AbstractAction.MNEMONIC_KEY, action.mnemonic);
}
public void actionPerformed(ActionEvent e) {
model.executeAction(action);
}
};
return actionImpl;
}
so I get the actions like following (in the Controller) and I assign them to the target Swing components:
private AbstractAction exitAction = getAction(Action.EXIT);
private AbstractAction flag_1Action = getAction(Action.FLAG_1);
private AbstractAction flag_2Action = getAction(Action.FLAG_2);
private AbstractAction helpAction = getAction(Action.HELP);
private AbstractAction aboutAction = getAction(Action.ABOUT);
private AbstractAction complexAction = new ComplexAction("Complex");
...
view.setExitAction(exitAction);
view.setAboutAction(aboutAction);
view.setHelpAction(helpAction);
...
where ComplexAction is a full implementation of AbstractAction, which is just an example of management of an action non listed in the enum class (because it's not a "common" action) but something deserving a custom full implementation.
Finally the "general purpose" executeAction method in the Model is responsible for dispatching the action to the specific sub-model class:
public void executeAction(Action action) {
Object obj = getModelInstance(action.modelObject);
if (obj == null) return;
Method method = null;
try {
method = obj.getClass().getMethod(action.modelMethod);
...
where getModelInstance just retrieves an instance of the target sub-model object from a model factory, given the model's class name listed in the enum.
Everything works fine, but I'm not convinced of this pattern: is this not boilerplate code? Are there some J2EE objects achieving the same results by writing less code? I have the feeling this is a very common pattern, and it seems strange to me that there isn't a better way do implement the MVC pattern using AbstractAction.
Create an abstract class that contains implementations of
Action. The exact formulation depends on your domain, butEditorKitmay serve as an example. As suggested here, concrete editor kits "export usefulActionclasses that operate on theDocumentmodel common to text components." More discussion may be found here, here and here.