MVC design question - java

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.

Related

What is a nice way to bind buttons to model-methods through a controller in Java using Swing and MVC-pattern

I have tried to adhere to the mvc pattern in the java code that I have written. I want to keep the view and model independant of the controller and from each other. I am also trying my best to use interfaces to keep things modular.
My view has JButtons that I want to "bind" to specific methods in the model through the controller. I have tried two approaches to still keep the view independent of controller:
Registered the controller as an ActionListener to the view-object. Pros: The void addListener(ActionListener listener) abstract method encapsulates this behaviour in the view interface, so more buttons can be added without changing the interface. It also decouples the controller from the view, since it does not know anything about the actual buttons in the view. It is also easier to add more views or more controllers, so it follows the open-closed principle well. Con: For the controller to know the nature of the ActionEvent, I have only been able to come up with using the ActionEvent.getActionCommaned() in a switch statement, so mapping each case to its' corresponding method in the model. This seem unsafe and prone to cause irritation, since it seems like bad practice to match strings like this.
I also came up with adding public addActionListener(ActionListener) methods for each button in the view, like addGasButtonListener(ActionListener). Then doing something like view.addGasListener(e -> model.gasVehicles(view.getGasAmount())) in the controller. Pro: This seems like it reduces the uncertainty of matching strings. Cons: It means I have to add these new methods to the view interface, and each time a new button is added I have to do the same, making it difficult to add new views that does not have anything to do with some of the methods.
Main question:
I prefer the first method since it seems better to me, but I still would like to find a way to avoid matching strings, and find some nice way to do it (more similar to the rigidity of the second way of binding buttons to methdods). Is there?
Follow-up (less important) question:
I should also mention that my controller contains an inner class TimerListener implements ActionListener, that contains the loop of the app that acts on ActionEvents from the Timer. It also acts on ActionEvents from buttons if approach number one is used, which is why my follow-up question is: how would I seperate this main loop that only cares about the timer, from the switch statement used to act on button events. Since the ActionEvent.getActionCommand() is null almost all the time, it would be nice to seperate the two. Is there a approach that would let me do that?
I don't really see the value of working with ActionListener instances in the first place.
From your own example:
view.addGasListener(e -> model.gasVehicles(view.getGasAmount()))
You don't do anything with the actual event
In case you decide to use a different UI element in the future that doesn't fire ActionEvents, you will have to change the type of the listener.
I would rather expose a custom listener/callback that the controller (or model) can register on the view:
void onGasAmountChange(double gasAmount);
That being said, you might be focusing too hard on having a model, view and controller. If you look at more complicated Swing components (JList, JTable, ...), they have a view component and a model (ListModel and TableModel).
You could do something similar and create your own model for your view, and let the view call the necessary methods on the model directly (just like it happens for those Swing components).
That avoids having to write a bunch of one-liner listeners that basically delegate to the model.

GXT template event handle in list

I am using Sencha's GXT 3.0 to render a ListViewCustomAppearance with a custom render defined through XTemplate (html/css). It works well when things are read only or when the interaction occurs on the list-level (ie. item select, item deselect).
How do I add mouse events to elements defined in the template's markup? My end goal is to have a clickable element inside an item in the list. The event handler would be in java.
Please let me know if this is going about it the wrong way..
ListViewCustomAppearance is useful when you want to completely restructure the child dom, not just how each child gets drawn. By making one of these, you are taking over responsibility of deciding how to handle selection (see the com.sencha.gxt.widget.core.client.ListViewCustomAppearance.onSelect(XElement, boolean) method).
This is important because ListView already knows how to manage selection! You can set and configure a ListViewSelectionModel on the ListView itself to handle a variety of interactions, and can listen there for events.
Instead, consider just making a custom Cell (probably starting from the AbstractCell class) that renders your data how you want it to look. Override the render method to specify how to append new content.
One more tip - the ListViewSelectionModel idea may not work for you, depending on what kind of data you are trying to get about user interaction. Instead, consider also overriding the onBrowserEvent method - this gives you the model object of the item that was modified, a reference to the root of the rendered content (from your render method), and the event itself. Use the event object to see what happened (test the event.getType() against a string event type). When subclassing AbstractCell, you also need to pass the event you are interested in to the superclass constructor.
Check out ActionCell as a pretty good example of how to rough this out. It is designed to be abstract enough to be reusable, but that also tends to make it a poorer example.

In HMVC how to send model change event to multiple views?

I can see several ways of doing this.
Have a reference to a single controller in the model. Model sends event to this controller and other controllers get to know it through the hierarchy and passes on to views
Have all interested controllers be listeners on the model (the model has a list of listeners ). The view gets to know the change through the controller
Have all interested views be listeners on the model. ( The view gets to know the change directly)
Which is appropriate and why?
your third Option is old school. The views get notified by the model, and the view decides how to handle this. It's okay but other options are better.
your second option sounds good. The views get notified by the controller(make sure you have different controller for updating the views and updating the model). So the controller can modifiy the events before passing them to the view. The controller can hier customise the Data for the views. the View shouldn't do this, there job is only to show something(in option three the views have to do this).
your first option is a small improvment of option two with a hierarchy. It's may be better in a complex scenario, to filter the event passing. But normaly this will blow up the overhead. So it is harder to read.
I would choose option two. It's the best trade of simple code and the option for complex actions.

Apply the MVC pattern to an existing application

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.

How do you make a class listen for PropertyChangeEvents caused by other classes, but not this class?

As described in another question, I have a set of Model objects and an associated set of Panel objects which allow the user to access the data in the Model objects. The Panels are registered as PropertyChangeListeners for the Models, such that if something else updates a value in a Model, it fires a PropertyChangeEvent, and the Panel receives it and knows to resync its values from the Model. (Currently I'm naively just updating all the values, but this could be made more intelligent to pull only the changed property.)
All of this makes sense when a Model is updated by some arbitrary, unknown source, which does happen in my application. However, most often a Model's properties are set by the Panels themselves. In this case, now that I've hooked the Panels up as PropertyChangeListeners for the Models, my code is doing something that makes no sense: after the Panel updates the Model, the Panel receives a PropertyChangeEvent from the Model and pulls the same value from the Model that it originally sent to the Model in the first place. No update needs to occur, and it makes no design sense for this to happen.
So how do I register something as a PropertyChangeListener but then say "Don't notify me of PropertyChangeEvents when I am the source of them?" (Note that I can't answer this by calling PropertyChangeEvent.getSource(); it'll give me my Model, not the Panel that sent the value in the first place; there's no way to look at this and tell what changed the Property.)
In all reality, do you really care if you get that event fired back at you? It allows you to handle any times the Model is changed outside the Panel and there really isn't a lot of overhead involved in checking to see if you actually have to update the value.
The PropertyChangeEvent holds the property being changed as well as the old and new values. You can check each incoming event to see if the value in the Panel is the same as the new value, and if it is then discard that event. The Model should tell everyone that is listening to it for PropertyChangeEvents every time it has changed otherwise it will need to know too much about the Objects that are listening to it.
Whatever you do, DO NOT create property change event listener loops. You will end up with a situation that very easily can end in an infinite loop if you are not very careful.
I don't think that there is any measurable detriment by the unneccessary repaint during runtime. So from that point of view there's no need of changing the code. In that situation you should decide having regard to design/architecture. You say:
...and it makes no design sense for this to happen...
, but it does!
If you want to avoid the repaint, you have to add the source (the panel) to the parameters of the method(s) that change(s) the model, put it into the change event and consider that parameter when evaluating the event again, which makes your code much more complicated. Think what else you have to do, if there are two instances of the same panel, one that changes the model, one that has to be changed after receiving the event...adding object-ids to method calls...What if later changing the design of model or view the way that editing one field of the panel leads to changes of the model that are shown in another part of the panel - additional changes again...etc.
Moreover, if you would do as described, you'll break with the decoupling of model and view, which is never a good idea.
If you want to keep it simple, leave it as it is. The only reason to write complicated code is bad results during runtime and I don't think you'll get that.

Categories

Resources