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.
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?
The user selects an element in the table, and clicks on a delete button.
The view delegates the action to the controller.
The controller access the table through an accessor on the view, and performs the update.
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?
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 :-)
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.
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:
For a large application, identify a small component. (The low-hanging fruit).
Identify what code effectively controls that component. This is probably another 'view' class in this case.
Separate the component identified in step one into a clean design.
Explicitly configure the owner (view) identified in step to as the controller for the newly refactored component.
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.
Related
In my program the controller just hooks keypresses with a function.
So should ikeep a reference to it?
E.g.
keeping a reference
Model model = new Model();
View view = new View(model);
Controller controller = new Controller(model,view);
or no
Model model = new Model();
View view = new View(model);
new Controller(model,view);
Inside Controller
public Controller(Model model, View view)
{
this.model = model;
this.view = view;
view.setOnKeyPressed(this::doSomething);
}
public void doSomething(KeyEvent event)
{
System.out.println("key pressed");
}
Maybe I implemented the Controller class wrong and misunderstood mvc pattern. But with what i wrote so far there is no reason for me to keep a reference to the controller object.
I'm not sure this question is really answerable, as it is probably too broad and/or too opinion-based. However...
MVC is a very loosely defined pattern. It really goes back about 40 years (or more) to the very early days of research into GUI development at Xerox PARC. Since it's been around so long and its primary use case (GUI architecture) has evolved significantly, it has branched into a number of sub-patterns and variations. Consequently, you'll find that "MVC" means many different things to different developers. In particular, MVC in a web application environment is somewhat different (imo) to MVC in the context you are talking about, because in a web application environment it has to sit on top of the request-response cycle. The rest of this answer/discussion focuses on the original "thick client" version of MVC, in which the view and controller are both in memory within the same process,and can communicate directly (rather than via a request-response protocol such as HTTP).
For me, the definitive guide to MVC in a desktop GUI context is Martin Fowler's essay on GUI architectures.
I would say that "classical" MVC is characterized by:
Having three components:
A model, which provides access to the data, may provide mechanisms for registering listeners for notification of changes to the data, and has no knowledge of the presentation of the data
A view, which observes the data in the model and updates itself when the data changes (this distinguishes classical MVC from some forms of MVP)
A controller, which provides the "view logic": typically this means it responds to user input and updates the model (not the view) as a result
So the model should know nothing at all about the view and the controller. The view doesn't know anything about the controller, but needs a reference to the model so it can display the data, and observe the data for changes, updating the presentation accordingly. The controller also needs a reference to the model, so it can update the data according to user input. Usually, the controller also needs a reference to the view, as it typically needs to register event handlers with the widgets in the view in order to know about user input it has to process.
The driving force behind this design is to allow multiple presentations (think of presentations as a combination of a view and controller) of the data which are kept synchronized. The pattern achieves this by referring everything though the model: one presentation's controller might update the model; since all the views observe the model, they all see those changes and each responsible for updating themselves accordingly. The controller that changed the view does not need to know about any other views that may be observing the data in order to keep all views in sync.
Your application itself will certainly need access to the model; it probably needs to access the data, maybe modify it from external (i.e. not user-driven) factors, persist the data at shutdown, etc. Your application probably needs access to the view (it needs to display it somewhere, may need to dispose of it at shutdown, etc). Your application may or may not need access to the controller. In its purest form, once the controller knows how to observe the view for user events, and knows how to update the model, you never need to communicate with it again. (If you want to change states from "external" events, you do so through the model, not through the controller(s).)
Several variations of this idea have emerged (see Fowler). One popular one (which also have several variations of its own) is Model-View-Presenter. In this variation, the controller is replaced by a "Presenter" which takes on some, or even all, of the responsibility of updating the view. In one form of this (which Fowler calls "Passive View"), the view is completely free of logic and merely lays out the controls. The presenter processes user input, updating the view and the model when user input occurs on the view, and observes the model, updating the view if it changes. This variant has advantages in terms of testability and ability to debug, but there is arguably tighter coupling between the view and presenter than there is between the view and controller. (It is relatively easy to provide multiple controllers for a view; providing multiple presenters for a passive view gets much more complex, and the presenters usually have to have some knowledge of each other.)
JavaFX actually provides "out-of-the-box" support for this style of architecture, using FXML as a (usually passive) view, and providing convenient ways to hook into what it calls the controller (which is perhaps more of a presenter). JavaFX properties make it easy to write models which can readily be observed by a view or by a presenter as needed.
In practice, you'll usually find a hybrid of these works best in most cases. A medium-large scale application will use MVC/MVP-type patterns in multiple places, on multiple different scales. You will often find that it is convenient for the controllers/presenters to have some knowledge of each other and to communicate between them, in which case you will obviously need to keep references to the controllers.
So the answer to your question is probably just "it depends what you need". If you don't need a reference to the controller, there is no need to keep one. Indeed, in the standard use of FXML in JavaFX, the controller class is simply specified in the view (the FXML); the FXMLLoader instantiates the controller from that information and wires the view and controller together as needed. You often never even have a reference to the controller instance in your code at all. Though, as seen in this popular JavaFX question you can certainly get one if and when you need. In a completely "pure" classical MVC, all state change is made through the model, and the views observe it, so you would never need access to a controller. Fowler points out some nice examples where this doesn't work as cleanly as it sounds: firstly that some state, and associated logic, is really part of the view and has no place in the model, and secondly that the registration/notification mechanisms can make it very hard to debug your application.
You will need for a controller instance be created for you when a key is pressed on the GUI. So you will need it to be a Listener which listens to key presses.
Once you have a GUI listener registered, its the framework's responsibility to instantiate that controller and pass the view to that controller.
(So, you never need the handle to a controller - its handle is always with the framework.)
Next, when you are in the controller with the view, you determine which model to create or fetch based on the values in the view...
This is how all MVC's work...
I am attempting to develop a "Person database" Java Swing application, using MVC design paradigm with Observer/Observable. Here is a simplified abstract of M/V/Cs I am using:
App
AppModel
(Empty right now, possibly i'll store certain static application info such as version number here)
AppView
(Creates a JFrame and a few other Swing components)
AppController
(Instantiates AppModel, AppView and also a PersonController and a PersonListController)
Person
PersonModel
(Stores info for 1 person)
PersonView
(Displays a number of form fields inside a JPanel (i.e Name, Age, Phone number). Observes PersonModel.)
PersonController
(Instantiates PersonView. Observes PersonView. Instantiates PersonModel. Updates PersonModel.)
PersonList
PersonListModel
(Stores a list of Persons)
PersonListView
(Displays a list of persons with appropriate Add / Delete buttons. Observes PersonList.)
PersonListController
(Instantiates PersonListView. Observes PersonListView. Instantiates PersonListModel. Updates PersonListModel)
Also, a 'bootstrap', where the app starts. It creates a new AppController.
In the real application, there will be more (and different) Model/View/Controller objects but I want to keep this example simple.
I dont understand how I can go about 'merging' these seperate views into one UI while maintaining a good seperation of concerns.
Take for example the PersonListView. IMHO it doesn't need to care about the AppView (with the JFrame etc). PersonListView just needs to look at its own model and update itself accordingly. However, I cannot enforce that because the PersonListView's own Swing components need to be added to the Swing components of another view, the AppView.
So at the moment the AppController is instantiating its own View, plus indirectly a PersonView and PersonListView (via instantiation of their controllers). AppController then grabs the 'main' Jpanel for each view, grabs the 'parent' Swing components they should be added to on the AppView, and adds them.
This just doesnt seem the right way to do it to me. Im pulling Swing-related members from their hiding places and messing with them around inside a controller. In fact instantiating the model and view within the controller seems bad too, but I cant figure out a better way.
I've seen enough 'simple MVC' tutorials recently that I'm dreaming of the bloody things - but not one tutorial seems to go into the relationships of multiple models, views, controllers, especially where it concerns Swing. Maybe I am wrong and the App should have just one view? Maybe I need a 'Relationship' class that sort of takes every single Model/View/Controller and instantiates stuff appropriately?
Any advice would be most appreciated as Im completely at a loss!
This is where a strict MVC paradigm falls down (in Swing anyway, and it may explains why Swing is written the way it is).
Swing combines the view and control elements together, leaving the model separate. That means, you are free to add a view to any other view and the control follows (the model remains dynamic).
I have a developer who insists on using the strict approach to MVC and they still can't tell me the order of precedence. ie should the control know about the view or should the view know about the control - which one plugins into the other. Personally, I'm to lazy and simply follow the Swing implementation.
To my mind, if you want to follow a strict MVC, I'd basically allow for a public method in your controller that allows access to the overall view (say a JPanel with all the components on it that makes up the view for example).
Think about the JComboBox or JSpinner for example. They both have a number of components that make up the view (editors, buttons, etc), but you have single access point, the component itself...
Your next problem is going to be how to combine various views into a single over all view.
Personally, I would create a group controller of some kind that allowed you to supply the various, known, controllers together (setPersonList for example), as the "master" controller is going to need to know about these other controllers any way, as it needs to know how to layout them out.
IMHO
Just a note, I'm new to MVC.
I'm trying to make my code as much decoupled and testable as possible.
I have a view with a text box and button.
I want to enable the button when a new text is entered and respects a certain criteria.
Ideally, I'd like this logic that decides if the button is enabled or not outside the view so it can be unit tested.
My understanding of MVC goes like that:
In my View I have a reference to my Controller.
In my Controller I have a reference to my Model.
In my Model I have a reference to my View.
Can you tell me if the following is a good design.
I added a boolean to the model buttonEnabled.
the sequence of event is like that:
Text is input in the text box, the text box has a listener. The listener calls a textChanged method on the Controller, the controller does the checks on whether to enable the button or not, and then sets the buttonEnabled of the Model through a setButtonEnabled accessor.
The accessor changes the value of buttonEnabled, and calls a buttonEnabledChanged() on the view (which exposes that method)
the idea is that the view is specific observer of the model, and the model is an observable which could theoretically have multiple views, and can call buttonEnabledChanged() on all of them.
Please let me know what you think.
This is a philosophical answer to a philosophical question :)
What you suggest could be correct. But the real question is if buttonEnabled is really a good candidate for your model. It's a purely gui thing and makes no sense being there. Thing that are really specific to the interface belong in the view, and nowhere else.
Now there might be a reason that the button is disabled (like, entry is not valid). Then you could just give it another name in the model (isValid). The translation from !isValid to !buttonEnabled would then become part of the controller, or even the view itself.
But I'm guessing that, in your case, the only reason to block the button when there is no content is to make it less likely for the user to send in a blank form. In that case, I would do the check in view completely (javascript if it's web), just for user convenience. In the model, just throw an exception (IllegalArgumentException seems likely) if the empty string gets there anyway.
If you're unit-testing your model, it makes a lot more sense to test if it will complain about an empty string, then to check if your model is setting buttonEnabled to false. If you really want to test gui functionality, there are solutions for that (for web, selenium comes to mind).
What you suggest is overcomplicated and, in my opinion, wrong from the standpoint of MVC.
The controller should not check whether or not to enable button, it is the task of model.
The model should not call any methods on view.
You have too specific methods. This desire to update only specific stuff, like buttonEnabledChanged() will make things overcomplicated in future, where components depend on each other through some business logic.
What you need is to bind this text box's value to model value, perhaps through the controller. So, changing text boxes value will change model's value. It should then call the update on the view. The view knows, that in the model there is some property that determines if the button should be enabled. It shouldn't be called isButtonEnabled() because it is agnostic of the view. It should be called isTextMatchingCriteria or something. Based on the value of that property, the view decides whether to enable the button or not.
This way:
Controller only controlls. It is catches and delegates, updates, but doesn't decide anything on business logic.
The model is independent of view.
View doesn't have any specific methods that can be called separately. The only thing it can is to render a correct presentation based on the current state of the model. It also specifies, what one or another state of the model mean on the screen - a disabled button or error message. The model shouldn't do that.
I'm already using Guice for the data model of my app, and so far I'm quite happy with it. However, the GUI part is about to become a Big Ball of Mud. I find it hard to use Guice here, because Swing components and models are tightly coupled, and often force a certain initialization order.
My application consists basically of a header with a lot of filters, a central and quite complex JTree component, and a lot of actions (e.g. from a JPopup), menus, dialogs, wizards etc. The main problem is that I have a lot of coupling between the components and actions (e.g. complicated validations, tree updates...). Could you give me some advice how to structure that GUI with Guice?
I'm aware of libs like GUTS, but the documentation is really thin, I'd rather avoid to add another dependency to my project and to learn another API (e.g. I don't know the Swing Application Framework).
I'd rather suggest a proper MVC, even better Presentation Model - View - Controller. Separate your code properly and Guice will fit in naturally. For example:
View classes should have a building part which draws the static content (labels, the tree, buttons, etc) and updating code which reacts to changes in the Presentation Model. All the action listeners should invoke some code on the controller. Both the Presentation Model and the controller should be injected by Guice, like all the other dependencies.
This organization would allow for easy testing with replacing the View with some testing code which will listen to changes in the Presentation Model and invoke actions on the controller.
I would advise to look at Guts-GUI.
It is a Swing UI framework based on Guice dependency injection model.
I think the problem is probably the overall architecture. You probably want to see if you can refactor the application to be simpler and more modular. Like Boris recommended, I would also suggest using the Presentation Model pattern - search for Martin Fowler and Karsten Lentzsch - and the JGoodies library.
For the problem with Actions, see how the Swing Application Framework and Netbeans Plaform handle them. For example, if an Action is used in both a view and a menu, you might want to make it available through a global map.
We have recently started on GUICE with swing. Here's what we have done which may be of help to you.
a. When you want to inject a model into a table/tree you could inject a model provider instead and do a provider.get() to get the model in the contructor.
for example
public class Mytable extends JTable {
public Mytable(Provider<MytableModel> modelProvider) {
this.setModel(modelProvider.get());
}
}
b. You could make a model generic and make use of the same model in different tables.
c. The model could have a handle to datasource which could be injected by a factory where necessary with assisted inject. Number of examples available in stack overflow.
d. Your model could be a flexible data structure which uses model to return the relevant cell/leaf/other value.
e. When you have actions, you inject actions in your component builders and attach them to relevant components.
f. Use #Singleton annotation where you have a shared object such as model injected in 2 different objects, such as action and the component.]
g. Use custom scope when you need to use number of instance sets of objects. Custom scopes are great for this as it keeps the code really clean.
Hope the above helps...
I would like to start a discussion on separating pure model and UI model in Spring 3.
By pure model I mean main object/objects that I retrieve from database, let's say some "user account". It contains enough info to display it in HTML view or to pass it to web service.
By UI model I mean all the auxillary stuff I need in UI to work with that object. E.g. if a "user account" has "state", then I need to fetch all the "states" from the database for, say, a combo box. The views are tricky and in some cases they require more information, in others - less. It would also be nice to be able to alter some lists by adding items like "Select all", which is pure UI stuff (and not quite conveniently done from view template).
I heard there's so called Model-View-ViewModel pattern, which seems to address these issues, but I have never tried its implementations.
The solution I use right now is to break logics into two services - one for pure model and one for UI model. It looks like this:
#RequestMapping(value="app/user_accounts/{id}")
public String getUserAccount(#PathVariable("id") String id) {
service.getUserAccount(id); // Gets main object and puts it into model
presenter.formUserAccount(); // Gets all classifier for main object's properties
return "user_account";
}
What I dislike about this is that the view and its so-called view model are not attached to each other. I can call presenter.formUserAccount() and return totally unrelated view name.
Another approach I see is similar to Spring controller annotation. We have classes annotated as #ViewModels and methods which map to view names. An interceptor finds and executes these methods before rendering a certain view. These seems elegant enough, but requires much code writing.
How would you solve this problem?
I have been thinking about this in the context of Grails, which is based on Spring MVC. My approach is to use Command Objects as View Models as it gives you the data binding and validation features that you would want in a View Model. With Command Objects you can abstract your "Pure Model" (or Domain Model) out of your View by using the Command Objects to map the view properties onto you domain objects.