Go ahead, I need to apologize for the small long mail, but it has been listening to me for quite some time. I recently read a lot about MVC and how it takes its place in the Swing Java world, and I still canβt understand why it is even remotely useful in any application that is a little more complicated than simple examples of toys that provide educational benefits. But let me start from the very beginning ...
I executed all my GUI programs in C # /. NET 4.0, which was not extensive enough but extensive enough to get a good idea of MVVM - this is the new version of MVC. This is a fairly simple concept: you define your GUI using XAML (XML, for example, a description of comnponents), defining the bindings between, for example, a table and its model, the string values ββof text fields. These bindings correspond to the properties of the object, which you define completely separately. Thus, you have a complete denouement between the gaze and the rest of the world. In the upper part, all changes in the model βalmostβ automatically return to the corresponding controls, the event-driven design is much more central, etc. Etc.
Now, back to Java, we need to use the old MVC school. Let me start with a very simple example: I'm trying to create a panel with two combo boxes and one button. Selecting a value in the first combo will drive the values ββof the second combo box, selecting a value in the second, will call an external service based on the values ββin both lists, and the button will have reset values ββin the first combo using an external service. If I did this using the βmyβ approach, I would do the following:
public class TestGUI { private JComboBox<String> firstCombo; private JComboBox<String> secondCombo; private JButton button; private ExternalReloadService reloadService; private ExternalProcessingService processingService; public TestGUI(ExternalReloadService reloadService, ExternalProcessingService processingService) { initialise(); this.reloadService = reloadService; this.processingService = processingService; } private void initialise() { firstCombo = new JComboBox<>(); secondCombo = new JComboBox<>(); button = new JButton("Refresh"); firstCombo.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String value = (String) ((JComboBox) e.getSource()).getSelectedItem(); reloadSecondCombo(value); } }); secondCombo.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("model")) { ComboBoxModel model = (ComboBoxModel) evt.getNewValue(); if (model.getSize() == 0) { String value = (String) model.getSelectedItem(); processValues((String) firstCombo.getSelectedItem(), value); } } } }); secondCombo.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { processValues((String) firstCombo.getSelectedItem(), (String) secondCombo.getSelectedItem()); } }); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { resetValues() } }); } private void processValues(String selectedItem, String value) { processingService.process(selectedItem, value);
Obviously, this is not a simple piece of code, albeit a short one. Now, if we did this using MVC, the first step would be to use some kind of controller that would do all the work, for example.
public class TestGUI { private JComboBox<String> firstCombo; private JComboBox<String> secondCombo; private JButton button; private Constroller controller; public TestGUI(Controller controller) { this.controller = controller; initialise(); } private void initialise() { firstCombo = new JComboBox<>(); secondCombo = new JComboBox<>(); button = new JButton("Refresh"); firstCombo.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String value = (String) ((JComboBox) e.getSource()).getSelectedItem(); Data d = controller.getReloadedData(value);
Problem 1: The view should not know anything about the controller, but it is better to respond to updates from the model.
To overcome the above, we could as a model. The model would simply have two lists, one for each list. So we have a model (completely useless) , a view and a controller ...
Problem 2 How do we do this? There are at least 2 separate methods: direct vs observer pattern
Problem 3 Direct wiring - Is it not just rewriting everything in the initial setup into three separate classes? In this approach, View registers the model, and the controller has both a view and a model. It would look the same as:
public class TestGUI { private JComboBox<String> firstCombo; private JComboBox<String> secondCombo; private JButton button; private Model model; public TestGUI(Model m) { model = m; } public void updateSecondValues(){ model.getSecondValues();
This is much more complicated than necessary, IMHO, which allows you to simulate and control each other all the time: view β (do sth) controller β (update yourself) view
Problem 4 The observer pattern is even worse in my opinion, although this allows us to separate the view and the model. The view will be registered as a listener on the model, which will inform about any changes. So, we need a method like:
public void addListener(ViewListener listener);
and we need a ViewListener. Now we can have one method with some event parameters, but we cannot serve ALL scripts in one way. For example, how would View know that we are just updating the second combobox and not resetting all the values ββor not disconnecting anything or not removing an item from the table ??? Therefore, we will need a separate method for each update (to a large extent, copy and paste the methods that we will use in gui in the listener), making the listener huge.
Main problems
As I raised a few questions here, I wanted to briefly summarize this.
Main Probelm 1 Splitting loginc into several objects: if you imagine that you have several panels with a large number of controls, you will have a view, model and views for all of them, which will lead to three times: many classes, as usual, allowing you to do work on a user interface class.
Main Problem 2 No matter what wiring technology you use, you end up adding methods to all objects to provide a connection that would be redundant if you just placed everything in the user interface.
Since "posting everything in the user interface" is NOT a solution, I am trying to get your help and comments on this. Thanks a lot in advance for your ideas.