Question

I't trying to follow MVC pattern. In internet as I see the most famous example is calculator, for example here. I began to use this implementation of MVC pattern. But now I have some doubts about action listeners in controller as they tend to move to view.

The main reason that there a lot of changes linked to view - fonts, colors, borders etc. Besides there are actionlisteners which modify only view! As a result to implement such actionlistener in controller is much more difficult (comparing to a simple internal anonymous class in view). Besides it requires to make many view element accessible from controller.

I had an idea to keep some actionlisteners in controllers and some in view, but it can lead to confusion in future. So I'd like to hear other people thoughts.

P.S. This question is not duplicate of MVC pattern with many ActionListeners

Was it helpful?

Solution

MVC is not a "strict" pattern. There are different interpretations of the original pattern, and different derivatives like MVP or MVVM that are often used (even when people say that they are using MVC).

The most important aspect is to separate the Model and the View. But the details about how they are connected may vary, depending on the application case.

The most frequent question that arises for the MVC pattern is: "What is a Controller?"

The answer:

"An accountant who got promoted"

From my personal experience, there's rarely a reason to have an explicit "Controller" class. Forcing the Listeners to be accumulated and summarized in one "Controller" class has several severe drawbacks. In order to establish the connection between the GUI components and the Model, you have two options: One option is to allow access to the view components in order to attach the listeners:

gui.getSomeButton().addActionListener(myActionListener);

I think this is a no-go, because it exposes implementation details and hinders modifications. The other option is slighly better - namely to offer methods that allow attaching listeners:

gui.addActionListenerToSomeButton(myActionListener);

But I think that this is questionable, because it still exposes the fact that there is a button. The problem might become more obvious when you have, for example, a JTextField to enter a number, and later change this to be a JSlider: It will change the required Listener types, although it should only be an issue of the view.

In Swing applications, I think that the Listeners can be considered as "little controllers". And I think it's perfectly feasible to have anonymous listeners that directly call methods of the model (unless there's additional logic to be wrapped around these calls).

Having said that: I would not consider the example that you linked as a "good" example for MVC. First of all, because the chosen example does not show the key point of MVC: The model does not contain a state, and the fact that the model in MVC usually is the thing that has to be observed (and thus, as Listeners attached) does not become clear. And secondly, because the way how the connection between the GUI and the Model is established is questionable due to the points mentioned above.

I liked the example at http://csis.pace.edu/~bergin/mvc/mvcgui.html . Parts of it could be questioned as well (for example, the use of the generic Observer/Observable classes), but I think that it nicely shows the basic idea of MVC in a convincing way.


EDIT: There is no download of this example in form of a ZIP or so. But you can just copy&paste the TemperatureModel, TemperatureGUI, FarenheitGUI and MVCTempConvert into an IDE. (It assumes a CelsiusGUI to be present. This CelsiusGUI, is omitted on the website, but structurally equal to the Farenheit GUI. For a first test, the line where it is instantiated may just be commented out).

The option to add listeners is in this example offered by the abstract TemperatureGUI class. The actual listeners are created and attached by the concrete FarenheitGUI class. But that's more or less an implementation detail. The key point here (that also aims at the original question) is that the Listeners are created by the View, in form of inner classes or even anonymous classes. These listeners directly call methods of the model. Namely, to set the temperature in Farenheit (for the Farenheit GUI), or to set the Temperature in Celsius (for the Celsius GUI).

There are still some degrees of freedom. It's not a "perfect" or "universal" MVC example. But it is IMHO better than most other MVC examples that I found so far, because it shows the important aspects nicely:

  1. The Model is Observable
  2. The View is an Observer
  3. The "Controllers" (that is, the Listeners in this case) are anonymous/inner classes that are soleley maintained by the view, and call methods of the Model

In a more complex, general setup, one would not use the Observable/Observer classes. Instead, one would create dedicated listeners and probably events for the model. In this case, this could be something like a TemperatureChangedListener and TemperatureChangedEvent. The Observable/Observer classes have been used here for brevity, because they are already part of the standard API.

Agin, note that there may be more complex application cases where the idea of MVC that is sketched in this small example has to be extended slightly. Particularly, when there are tasks to be performed that go beyond just calling methods of the model. For example, when the View contains several input fields, and this data has to be preprocessed or otherwise validated before it is passed to the model. Such tasks should not be done by an anonymous listener. Instead, such tasks could be summarized in a class that then may be called a "Controller". However, attaching the actual listeners to the GUI components can still be done solely by the View. As an overly suggestive example: This could then happen like

// In the view:
someButton.addActionListener(new ActionListener()
{
    @Override
    public void actionPerformed(ActionEvent e)
    {
        String s = someTextField.getText();
        Date d = someFormattedTextField.getDate();
        int i = someSlider.getValue();

        // The controller validates the given input, and
        // eventually calls some methods on the Model,
        // possibly using the given input values
        controller.process(s, i, d);
    }
});

OTHER TIPS

I usually follow the following design pattern and it works well for me as it separates the model view and controller quite effectively

View: Your view should contain all your jcomponents with their getters or setters, component placing related code, layout related code. I never add any listeners to any of the component in the view class, it just deals with the layout

Model: Model should have placeholders to hold your data for your view, eg: if you have a JTable, model might contain a arraylist that will hold the data for your JTable

Controller = Model + view (here is where you bind the model with the view) add all your listeners here Bind your text fields, comboboxes etc add your client side business logic add your action listeners for your buttons This is where you should access your view and model.

Hope this helps.

If you follow the Controller GRASP pattern, which assumes you separate interface and domain layers, the actionPerformed() code stays in the interface layer. The concept is explained in the book, but I include a figure from the instructor resources of the book for clarity:

enter image description here

Edit: As I said in a comment above, if you implement a different view (say, on a mobile app, or to add voice recognition), you want to keep the same system operation sent to your domain layer. To me, I like the notion of the view layer "recognizing a user gesture that gets translated into a controller command."

All logic should be placed in the controller. However there is no strict line, some very simple logic could be fine inside the view. Place actionListeners in controller and then your buttons in GUI. That's how I normally do. Sometimes I'm lazy and let my buttons implement actionListeners and let them listen on themselves, in this case i put buttons inside controller package.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top