3

This is a follow up question to The MVC pattern and SWING. I am trying to implement the MVC pattern in an existing piece of code. The existing code creates a JFrame which acts as both the view and the controller. The JFrame has a table, and the table's model is an adapter to a custom data model. Whenever the user performs an action, the model would be updated by doing something like the following:

CustomDataTableModel cdtm = (CustomDataTableModel) DataTable.getModel();
CustomDataModel cdm = cdtm.getModel();
cdm.delete(1);

I've tried to visualise how it currently works, but I've also visualised how I imagine the relationships with the future controller and model should be.

MVC

Now, my question is simply whether I can continue using the model as it is now? Could I implement the following and still "adhere" to the MVC pattern?

  1. The user selects an element in the table, and clicks on a delete button.
  2. The view delegates the action to the controller.
  3. The controller access the table through an accessor on the view, and performs the update.
  4. The model, when it is updated, notifies the JTable that it has been changed.

If any other components in the view displays data from the table, then this could be solved by registering listeners on the JTable's table model.

Update 1

I've been thinking about the existing code in light of the MVC pattern, and I've redrawn the relationships a little. The point is that the controller is the behaviour of the view, thus the controller updates the model when users do stuff, and the view listens for changes in the model. However, nothing in the MVC pattern stops the view from listening to the model through a tablemodel - right?

MVC

Now, the user clicks the add button. The view notifies the controller that the add button has been clicked, and the controller takes care of creating a new item by invoking some method on the model. The view is registered as a listener on the model (through a table model) and updates its view. The controller may also be a listener on the model in case it needs to take care of disabling or locking fields. Have I not achieved what the MVC is all about; separation of concerns? As far as I can see, I've even introduced the adapter pattern to decouple the view even more from the model? It is late and I am tired, so that might be why it makes sense :-)

Community
  • 1
  • 1
sbrattla
  • 5,274
  • 3
  • 39
  • 63

2 Answers2

3

In the general sense, I would advise you the following:

  • take a look at JGoodies Binding, it is not MVC but uses the "PresentationModel" pattern which is, in my opinion, better adapted to a whole application than MVC (which I find suitable for individual widgets only). This should solve your problem between your Domanin Model and the TableModel
  • if your application has only tables, then GlazedLists also makes a lot of sense: it will also isolate your Domain Model from your TableModel (but it doesn't enforce any global pattern, MVC or PM)

Regarding the current design you show, I would rather suggest that the View asks the Controller for an Action that the View will assign to the Delete button. Then the Controller can act on the Domain Model.

jfpoilpret
  • 10,449
  • 2
  • 28
  • 32
2

That gets messy and confusing fast, alas, and the code base is already confusing due to lack of separation.

I suggest instead migrating distinct components to a clean, simple MVC design. Such a component (which is currently a view, controller, and model all mixed up together) would then be separated in a clean fashion, however you will then have the difficulty of how to handle the controller and model? As a temporary workaround, you'll be forced to designate the owner view as the controller, so the owner arguably has more responsibility. I think that this is a suitable workaround, because you will eventually separate more and more components into an MVC design, and the views that are also controllers will eventually become refactored as well.

In other words:

  1. For a large application, identify a small component. (The low-hanging fruit).
  2. Identify what code effectively controls that component. This is probably another 'view' class in this case.
  3. Separate the component identified in step one into a clean design.
  4. Explicitly configure the owner (view) identified in step to as the controller for the newly refactored component.
  5. Repeat until there is clean separation between ALL views and controllers.

Be careful to ensure that the application is still working at the end of every 'step 4' above, otherwise, you'll find yourself in a mess that just gets longer and longer to fix. (Even if the end result is nice and clean, you may have missed your deadline).

Keep in mind that it may be difficult to extract the 'model' from the code at first - the controllers and views will be easiest to separate, but eventually, the models will become easier to separate as well. Whenever you manage to extract a model, write unit tests that test that model in isolation.

The presence of a well written suite of unit tests will help ensure that the application continues to have well-defined separation of concerns. (If concerns are not separated, then it becomes very hard to unit test), so the unit testing approach serves as a motivator.

I hope that makes sense.

Arafangion
  • 11,517
  • 1
  • 40
  • 72
  • Thanks for your suggestion! I understand from what you say that the data model not should be adapted to the JTable through a table model. Should I rather have the JFrame (view) to listen to changes in the data model (model), and then (on model changes) have the JFrame to synchronize the JTable's model with the data model? – sbrattla Mar 10 '11 at 11:50
  • @sbrattla: I confess I'm not that well versed on the specifics of a Java implementation, however, yes, you ultimately want to have the view listen to changes to the data, rather than having the controllers do ALL the work. In most of my code, however (dealign with windows forms), I don't go for a pure MVC approach, but instead go half way where the controller notifies the view of the new data. It works, and is (almost) as separated, just not as clean. (And more likely to have update cycles). The key to go for at first, is to get the crap separated. :) – Arafangion Mar 10 '11 at 12:19