3

I've always coded my graphical applications in Java by extending the JFrame class like so:

public class CalculatorApp extends JFrame {
    // GUI components are declared as member variables of JFrame
    private final JLabel answerLabel;
    private final JButton sumButton;
    private final JButton divideButton;
    ...
    
    // Create and display the GUI
    public CalculatorApp() {
        setTitle("A Calculator");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ...
        
        // Initialize components
        answerLabel = new JLabel("Your answer will appear here");
        sumButton = new JButton("Sum");
        sumButton.addActionListener((ActionEvent e) -> {
            sum();
        });
        ...
        
        // Make visible
        pack();
        setVisible(true);
    }
    
    // Actions performed by the user; these methods have access to
    // the GUI components to grab the user input (eg. TextField.getText())
    // and then update the GUI with the result (eg. answerLabel.setText()).
    public void sum() {
        ...
    }
    public void divide() {
        ...
    }
    ...
    
    public static void main(String[] args) {
        new CalculatorApp();
    }
}

Although recently I've learned that this is not very good practice since you're putting your specific application's function into a JFrame - something that really shouldn't have the function of a calculator, for example. I've found that trying to create applications with more and more features with this approach leads to really horribly organized code because there's no line between GUI & input verification code, and the actual application's features.

So what's the best way to structure a program like this?

I've outlined the only sensible alternative I could think of below.

Handlers

This structure separates the function of the application from the GUI by putting the GUI nicely into its own little class that can be created and shown, but has the drawback of having to manage a lot of annoying handlers. The handlers are a way to give the application function to the GUI. This structure is also easier to convert to other JWindows like JDialog because the entire class hierarchy doesn't have to be changed.

public class CalculatorApp {
    // Create the GUI and pass it the handlers
    public CalculatorApp() {
        new CalculatorAppGUI(
            new SumHandlerImpl(),
            new DivideHandlerImpl(),
            ...
        ).show();
    }

    // All of the application function is in the handlers
    private class SumHandlerImpl() implements SumHandler {
        public double sum(double a, double b) {
            return a + b;
        }
    }
    private class DivideHandlerImpl() implements DivideHandler {
        public double divide(double a, double b) {
            return a / b;
        }
    }
    ...

    public static void main(String[] args) {
        new CalculatorApp();
    }
}

public class CalculatorAppGUI {
    // Handlers that perform application function are stored as member variables
    private final SumHandler sumHandler;
    private final DivideHandler divideHandler;
    
    // GUI components are declared as member variables
    private final JPanel mainPanel;
    private final JLabel answerLabel;
    private final JButton sumButton;
    private final JButton divideButton;
    ...
    
    public CalculatorAppGUI(SumHandler sumHandler, DivideHandler divideHandler) {
        // Store handlers
        this.sumHandler = sumHandler;
        this.divideHandler = divideHandler;
        
        // Initialize components
        mainPanel = new JPanel(new SomeLayoutManager());
        
        answerLabel = new JLabel("Your answer will appear here");
        sumButton = new JButton("Sum");
        sumButton.addActionListener((ActionEvent e) -> {
            double answer = sumHandler.sum(/* Values from GUI */);
            answerLabel.setText(String.valueOf(answer));
        });
        ...
        
        mainPanel.add(answerLabel);
    }
    
    // Create a frame for the GUI and display it
    public void show() {
        JFrame frame = new JFrame();
        frame.setTitle("A Calculator");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        ...
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setVisible(true);
    }
    
    // Nested static handler interfaces
    @FunctionalInterface
    public static interface SumHandler {
        public double sum(double a, double b);
    }
    ...
}

The handlers in this case are very simple, but in a larger application they would be much more complicated operations like JoinGameHandler or whatnot. Here the application function and things like application state (connected to a game or not?) would be stored in the CalculatorApp class and all the GUI code would be in the CalculatorAppGUI class. The issue here is that a GUI with a lot of buttons and a lot of features leads to a lot of handlers which doesn't organize very well either (you could end up with a hundred handlers to store for a sufficiently complex application, which is just impractical).

In case it isn't already apparent, I'm 100% self-taught in the area of Java Swing and haven't really been exposed to the standards for this sort of stuff. All help appreciated.

Community
  • 1
  • 1
Parker Hoyes
  • 2,118
  • 1
  • 23
  • 38
  • One approach is examined [here](http://stackoverflow.com/a/11944233/230513). – trashgod Aug 15 '15 at 17:14
  • @trashgod I took a look at your link, but that doesn't seem to address my question. I am asking about program structure, not GUI design. – Parker Hoyes Aug 16 '15 at 00:07
  • `The issue here is that a GUI with a lot of buttons and a lot of features leads to a lot of handlers`. This is called inherent complexity. You can't expect the code that implements a complex application to be simple. The handlers approach is good. One handler per functionality is functional cohesion. Craig Larman defines a GRASP pattern called [Controller](https://en.m.wikipedia.org/wiki/GRASP_(object-oriented_design)#Controller), which is based on [system sequence diagrams](https://en.m.wikipedia.org/wiki/System_sequence_diagram) to separate presentation layer code from domain layer code. – Fuhrmanator Aug 17 '15 at 00:33

1 Answers1

2

I am asking about program structure, not GUI design.

No single design pattern will solve all GUI design problems, but many well-known patterns recur in GUI design. Some common heuristics may be helpful:

  • Use the model-view-controler and observer patterns as an aid to loose coupling; both patterns are examined here.

  • Use Action to encapsulate functionality; among the several examples cited here, KeyPadPanel may be the most relevant.

  • To manage copmplexity, use nested classes for ease in prototyping; as the need arises, inner classes can be promoted to separate classes having package-private access.

Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • 1
    Your point on the MVC pattern is what I was looking for; you had some good other points as well. I'd be interested to see what other people have to say on this topic, though. – Parker Hoyes Aug 17 '15 at 06:24