September 15, 2019
Hot Topics:

MVC in a Java/Swing Application

  • May 21, 2007
  • By Rob Lybarger
  • Send Email »
  • More Articles »

Spend enough time writing code, and you will eventually hear of the Model-View-Controller (MVC) paradigm: your data, business logic, and presentation should all be separate entities. Consider how J2EE applications use combinations of servlets and filters for the controller layer and JSP pages for the view layer of an MVC-based web application. With that being said, I have not seen as much effort directed at desktop application. Examples for Swing applications tend to lump the entirety of the control layer (and indeed even business logic) directly into the view layer—that is, into the various frame and panel classes.

In this article, I will present one way you might put some separation between the view and control components in a desktop application. The example I present will be, by necessity, rather simplified. It will be possible to code the entire demo application in one class. It may even be faster that way. However, larger applications with more complex requirements tend to not fit into the one-class solution category, and it is for these larger, more complex applications that you might appreciate having an extra design strategy in your arsenal.

The Demo App, Defined

Consider that you want a simple Swing-based application that allows the user to enter text and then have certain special characters be escaped. Specifically, you want to escape a few of the characters that would cause trouble in an XML or an HTML document: the greater-than, less-than, and ampersand characters. (How many online forum posts ran into trouble when the poster simply copied-and-pasted a big chunk of code without accounting for the special characters?)

Figure 1: Screenshot of demo application (Mac OS X platform)

As I mentioned above, this can be quite simply done in a single class that extends JFrame and implements ActionListener to pick up the button press. The actionPerformed() method could directly yank out the text from the text component, perform whatever operations needed to transform it, and then replace the text in the text component with the modified form.

What happens in the more elaborate applications where the button, text component, and frame class all need to be in separate classes? Certainly, it is still easy to make the program function, but where do you put the workhorse code? The simplest solution tends to put the workhorse code in the top-level frame class because it tends to be able to see all the UI components underneath it. This also becomes non-optimal as more and more workhorse code builds up in the top-level frame class.

What happens if you completely overhaul the layout of the user interface? Maybe a few panels appear to better organize existing components, a menu comes into the mix, or you change widget sets (such as from Swing to SWT) entirely. Maybe you want to add command-line batch capability where the UI is not even shown at all. The more you find the business logic that affects what information the user sees getting intertwined with the display logic that allows the user to see and manipulate that information, the more strongly (and needlessly) coupled they become. The event handling code for a button has to account for the new panels, for example. Designs such as these will hit a wall eventually.

Enter the Controller

An alternative solution I am presenting here involves the creation of a "controller" class whose job it is to contain the interactions of the user interface components and to interact with other "business logic" classes. This class is not a descendant of any Swing class—it is a direct subclass of the humble Object class. The controller will need to basically perform two functions: keep track of references to user interface components that will be updated or modified in some way (such as the text field in our demo), and provide a set of methods that other components can directly call in their event handler (such as the button in the demo).

The primary use case of the demo application is this:

  1. The user enters some text and then presses the button.
  2. The button's actionPerformed() method simply calls a method in the controller class.
  3. The controller class, storing a reference to the text component, grabs the current text value.
  4. The controller class uses a utility class to transform the text.
  5. The controller class inserts the modified text back into the text component.
Note: The controller does not, for the purposes of the demo, need a reference to the button itself because it does not take any actions that affect the button. It only affects the text component.

Designing the controller

The next consideration is how the controller class itself should be designed. My opinion is currently that, given the nature of what it is doing, only one instance of the controller class is ever needed. The user is, after all, single threaded with respect to their usage of the application. Given the way that various user interface classes might need to all interact with this single controller instance, a completely static-method class design might suffice. Instead, I prefer to go with a singleton design pattern for the controller, providing a static getInstance() method for all the user interface classes to utilize, but otherwise providing non-static methods for the event handlers to talk to. (The singleton class has a benefit over the fully-static class in that static methods do not inherit into a subclass, should you ever be faced with the need to so do.) Next, some setter methods need to be present to initialize the reference(s) to the interface element(s) that the controller needs to interact with. Finally, some methods need to be present that trigger something interesting to happen.

Tip: Where possible, I recommend that the controller class use the most abstract or most generic forms of user interface components possible. For example, you can use JTextComponent instead of JTextField or JTextArea, or JToggleButton instead of JCheckbox. This allows you to absorb a few user interface design changes with no impact to the controller class itself.

For the demo, the basic skeleton of the controller is:

public class AppController {
   //singleton class details
   private static AppController instance = null;
   protected AppController() { ... }
   public static AppController getInstance() { ... }

   //controller details
   private JTextComponent textComponent = null;
   public void setTextComponent(TextComponent tc) { ... }
   public void handleEscapeAction() { ... }
   public void handleExitAction() { ... }

Refer to the downloadable files for this article for the complete source code.

Page 1 of 2

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date