Façade clears complexity

Develop dialog boxes and Swing apps faster

I had been working at Sun Microsystems for just over a year when the mandate came from on high to switch to Java. In those days, you could become a Java expert in a scant few months, and we did, rewriting an existing C++ application in Java. Today, of course, it's a different story—novice Java developers must learn a huge API, including the basics such as collections, JavaBeans, input/output (I/O), Swing, internationalization and localization, and more, not to mention ancillary topics like Ant, Java API for XML Parsing (JAXP), log4j, JavaServer Pages (JSP), JSP Standard Tag Library (JSTL), JavaServer Faces, Java Message Service (JMS), Enterprise JavaBeans (EJB), Java Data Objects (JDO), AspectJ...the list goes on and on. Just keeping up with the onslaught of new technologies is more than a full-time job.

Object-oriented development helps manage complexity by encapsulating data and functionality in classes with well-defined interfaces, and Java lets you encapsulate classes in packages. But that encapsulation only goes so far; sometimes you have to delve into complex APIs to do even the simplest things, as EJB developers can attest.

Although object-oriented development fails to reduce the complexity of learning a new API, we can use its facilities to implement a design pattern that does: the Façade pattern, where objects known as façades offer a simple interface to complex subsystems so you can do something without knowing the subsystem's particulars. Let's see how the Façade pattern works.

Note: You can download the associated source code from Resources.

The Façade pattern

In Design Patterns, the authors describe the Façade pattern like this:

Provide a unified interface to a set of interfaces in a subsystem. Façade defines a higher-level interface that makes the subsystem easier to use.

Figure 1 shows the Façade design pattern's class diagram.

Figure 1. Façade class diagram

Java consists of high-powered APIs that let you do everything from developing killer graphical user interfaces (GUIs) to sending asynchronous messages between distributed objects. But those high-powered APIs can make it incredibly difficult to do the simplest things; for example, consider the "simple" GUI application that I discuss in "A Swing Application Façade" below.

The Façade pattern is easy to understand: one class provides a simplified interface to a subsystem. Façades make the easy stuff easy; for the hard stuff, you must delve into the subsystem itself. But façades typically accommodate a high percentage of a subsystem's use cases and, therefore, they are particularly valuable; so valuable in fact, that as we shall see in the "JOptionPane: Swing's Façade for Dialogs" section below, complex subsystems such as Swing's API for windows and dialog boxes often implement façades of their own that simplify their use.

This installment of Java Design Patterns examines two uses of the Façade pattern. The first discusses a built-in Swing façade that simplifies the use of dialog boxes, and the second examines a custom façade implementation that makes it easy to throw together a Swing application.

JOptionPane: Swing's façade for dialogs

Swing provides extensive facilities for windows and dialog boxes, from low-level functionality for creating, populating, and showing windows to high-powered features such as glass panes and choosers for selecting files and colors. Although you can do nearly anything with Swing windows and dialogs, it's not an easy matter to create even the simplest dialogs from scratch; for example, consider Figure 2's application that displays a home-grown message dialog.

Figure 2. A home-grown message dialog

Figure 2's application has a toolbar with two active buttons: if you click the left button, the application creates a message dialog from scratch and displays it; Example 1 lists the event handler for that button.

Example 1. Implement a simple message dialog

   JDialog dialog = new JDialog(this, "Error!", false);
      newButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            // Top-left panel:
            JPanel topLeft = new JPanel();
            topLeft.setLayout(new FlowLayout(FlowLayout.LEFT));
            topLeft.add(new JLabel(new ImageIcon("../graphics/stopsign.jpg")));
            // Top-right panel:
            JPanel topRight = new JPanel();
            topRight.setLayout(new BorderLayout());
            topRight.add(new JLabel("You must follow directions!", JLabel.CENTER), BorderLayout.EAST);
            // Top panel:
            JPanel top = new JPanel();
            top.setLayout(new BorderLayout(15,0));
            top.add(topLeft, BorderLayout.WEST);
            top.add(topRight, BorderLayout.EAST);
            // OK button:
            JButton button = new JButton("OK");
            button.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e) {
            // Bottom panel:
            JPanel bottom = new JPanel();
            bottom.setLayout(new BorderLayout());
            bottom.add(button, BorderLayout.EAST);
            // Dialog panel:
            JPanel dialogPanel = new JPanel();
            dialogPanel.setLayout(new BorderLayout());
            dialogPanel.add(top, BorderLayout.NORTH);
            dialogPanel.add(bottom, BorderLayout.SOUTH);
            Container cp = dialog.getContentPane();

The preceding code uses five panels (instances of JPanel) to construct the dialog's user interface; Figure 3 shows those panels.

Figure 3. Layout for a dialog

Figure 3's panels are arranged in a hierarchy like this:


The dialogPanel contains the top and bottom panels, and the top panel contains the topLeft and topRight panels.

Each panel in Figure 3 uses an appropriate layout manager in Example 1. I wanted the graphic left-justified, and the message and the button right-justified. I picked this configuration because it's the same as message dialogs created by Swing's dialog façade (see "Use JOptionPane" below for more information).

Although it's certainly not rocket science, Example 1 should convince you that creating dialog boxes from scratch is tedious work, which results in frequent trips to the Swing Javadocs for the average Java developer. Of course, wise developers would encapsulate that code in a class of its own for future reuse, instead of reimplementing the same functionality for future dialog boxes. Swing's creators were even wiser: they implemented a class—JOptionPane—that pops up the most common types of dialog boxes. Let's see how we can use JOptionPane to simplify dialog creation and display.

Use JOptionPane

Swing's JOptionPane, depicted in Figure 4, is a façade that creates different types of dialogs and displays them.

Figure 4. JOptionPane is a façade that creates dialog boxes

Example 2 shows a rewritten action listener from Example 1 that uses JOptionPane to create a message dialog instead of creating it from scratch.

Example 2. JOptionPane creates a simple message dialog

      openButton.addActionListener(new ActionListener() {
         public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(TLDViewer.this, "You must follow directions!",
               "Error!", JOptionPane.ERROR_MESSAGE);

Could any infomercial rival the amazing results you get from using JOptionPane? Compare Example 1 to Example 2 and decide which block of code you'd rather write the next time you need a message dialog. Thankfully, we have the Façade pattern.

A Swing application façade

Swing is one of my all-time favorite GUI frameworks, but even after writing a 1,600-page book on the subject, I have to refer to the book and Javadocs almost every time I write a Swing application. Just getting a Swing application off the ground can require heavy lifting, especially if you follow best practices by internationalizing your application. This section shows you how to implement a façade that encapsulates much of the grunt work involved in setting up a Swing application.

Figure 5's application is a library for cataloging books, DVDs, and VHS tapes.

Figure 5. The library in English. Click on thumbnail to view full-size image.

The application's features are unimportant to us, except for the fact that the application is internationalized and localized in English and French; Figure 6 shows the application localized for French.

Figure 6. The library in French. Click on thumbnail to view full-size image.

The library uses a façade—ApplicationSupport—I wrote so I could create Swing applications in a hurry. That façade provides the following methods:

  • Launch application:
    • public static void launch(final JFrame f, String title, final int x, final int y, final int w, int h)
  • Menus and locale:
    • public static JMenu addMenu(final JFrame f, String titleKey, String[] itstrong)
    • public static Locale getLocale()
  • Status area:
    • public static JPanel getStatusArea()
    • public static void showStatus(String s)
  • Internationlization:
    • public static String getResource(String key)
    • public static String formatMessage(String patternKey, String[] params)

Rather than show you the tedium involved in getting an application like the one in Figure 6 off the ground and then contrast it with the use of a façade, let's save some time and proceed directly to the latter. Example 3 illustrates how Figure 5's application uses the ApplicationSupport class.

1 2 Page 1
Page 1 of 2