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
.