I'm building a GUI application and try to adhere to the MVC principle as good as I can.
Therefore my model fires PropertyChangeEvents with the help of PropertyChangeSupport so the GUI knows what to update when.
The model of my application is nested, i.e. I have a main model class that contains some properties or Lists of other model classes which in turn might contain more model classes.
A simple example:
public class MainModel {
private int someData;
private List<Stuff> stuffList;
// imagine PropertyChangeSupport and appropriate getters/setters
// for both MainModel and Stuff
}
Now both MainModel and Stuff have PropertyChangeSupport. If someone listens to events fired from MainModel, it gets changes of someData and from adding/deleting to/from the list stuffList.
But what if someone wants to get events from changes made to the individual elements of stuffList? There are two possibilities:
The observer has to fetch the list of Stuff elements and register as a listener to each element separately.
The main model registers itself as a listener to the elements of stuffList when they are added and forwards these events to the listener of the main model.
This is how it looks like with the first approach:
mainModelInstance.addListener("new stuff element", new PropertyChangeListener() {
public void propertyChanged(PropertyChangeEvent evt) {
Stuff s = (Stuff) evt.getNewValue();
s.addListener( // ... and so on
);
}
});
I think 1. has the advantage of keeping the model clean and dumb but leads to code duplication (many UI elements have to listen to changes to stuffList and add themselves dynamically to the new Stuff elements, see above). With 2. its the opposite: The client code is not as messy but the model acts partly as a listener which somehow doesn't feel right. That's why I currently use the first approach.
What are your thoughts? Maybe I'm too harsh on myself and 2. is okay. Or maybe there is a completely different (and better) way?
For at least 20 years, I've programmed MVC models observing other models (like for doing what is now called MVP[resenter] or MVVM patterns), and here are some heuristics I'd offer...
(1) Views and Controllers are hierarchical, and GUI event handling has long recognized that by letting event listeners listen at different levels of the hierarchy (like directly at a button level, or at the entire web page level). Each event specifies the most specific component associated with the event even if a higher level container was being listened to (aka observed). Events are said to "bubble up".
(2) Models can equally be hierarchical. The Model-generated "update" event can also use the same technique as above, specifying in the event the most specific "inner model" associated with the update event, but allowing observing at the "outer" composite model level. Observer update events can "bubble up".
(3) There is a common paradigm for hierarchical models...the spreadsheet. Each cell is a model that observes the other models/cells referenced in its formula.
Related
How should Listeners etc be managed? I've found only examples with one button etc.
I can think of following options:
Extra class for each - doesn't seem right, especially when items
can be created dynamically
Class for each group (such as form1,
form2, controlButtonsOnLeft, controButtonsOnRight, mainMenu,
userMenu, ...) where I'll check which button/component caused this
(via getSource method for example)
Some super (sized) controller,
which will accept all user actions
New anonymous class for each,
which will call controller's method with parameters specifying
details (probably enums)
And another question: I've found many examples for MVC, I was wondering what is better (or commonly used) for app. developed by 1 person (app will not be huge)?
A. Viewer sets listeners to controller (A1-3)
B. Controller calls viewer's methods, which accepts listener as parameter (methods addLoginSubmitListener, addControlBoldButtonListener etc)
All of above are possible to implement and so far I would choose B4.
Meaning in Control I would do something like this:
...
viewer.addLoginButtonListener(new Listener()
{
#Override
public void actionPerformed(ActionEvent e) {
...
someButtonsActionHandler(SomeButtonEnum, ActionEnum);
...
}
});
...
private void LoginActionHandler(LoginElementsEnum elem, ActionEnum action)
{
if (elem.equals(LOGINBUTTON)) {...}
...
}
...
This combines readable code (1 logic part at one place in code), doesnt create any unwanted redundant code, doesnt require any hardly-dynamic checks, is easily reusable and more.
Can you confirm/comment this solution?
To be honest the question comes down to a number of questions...
Do you want reusability?
Do you want configurability?
Are they self contained? That is, does it make sense for anybody else to listener to the component or need to modify the resulting action of the listener in the future?
Personally, I lean towards self containment. A single listener for a given action/task. This makes it easier to manage and change should I need to.
If I don't need reusability (of the listener) or configurability, then an anonymous inner class is generally a preferred choice. It hides the functionality and doesn't clutter the source code with small, once use classes. You should beware that it can make the source code difficult to read though. This of course assumes that the task is purpose built (its a single, isolated case). Normally, in these cases I will prefer to call other methods from the listener that actually do the work, this allows a certain amount of flexibility and extendability to the class. Too often you find yourself wanting to modify the behaviour of a component only to find that behaviour buried within an anonymous or private inner class...
If you want reusability and/or configurability - that is, the listener performs a common task which can be repeated throughout the program or over time via libraries, then you will need to provide dedicated classes for the task. Again, I'd favour a self contained solution, so any one listener does only one job, much easier to change a single listener then having to dig through a compound list of if-else statements :P
This could also be a series of abstract listeners, which can build functionality for like operations, deleting rows from a table for example...
You could considering something like the Action API (see How to Use Actions for more details), which are self contained units of work but which also carry configuration information with them. They are designed to work with buttons, such as JButtons and JMenuItems, but can also be used with key bindings, making them extremely versatile...
The second part of you question (about MVC) depends. I prefer to keep UI related functionality in the view and out of the controller as much as possible. Instead of allowing the controller to set listeners directly to components, I prefer to provide my own, dedicated, listener for the controller/view interaction, which notifies the controller of changes to the view that it might like to know about and visa versa.
Think about it this way. You might have a login controller and view, but the controller only cares about getting the credentials from the view and authenticating them when the view makes the request, it doesn't care how that request is made from the views perspective. This allows you to design different views for different circumstances, but so long as you maintain the contract between the view and the controller, it won't make any difference...But that's just me.
Let's say I have a class that builds a GUI and has a method updateMainUI(String text) that appends text to a JTextArea. Currently, I'm using abstract classes and methods to update the field from a different class, but I'm wondering if this is the 'right' way to do it?
I now have three abstract classes that have an protected abstract updateUI(String text) method that I override in my GUI class to update the field whenever I need to, but I'm doing the same thing in multiple classes and now I feel like I need another class that does the exact same thing.
Is there a better or more acceptable way of doing this?
From you question, it's difficult to be 100% sure, but, it is generally encouraged to use a Model–view–controller approach to these types of problems.
This is, the model defines the "virtual" state, the view represents this state to the user and the controller controls changes to the model initiated from the view...
The view is notified, by the model, when it changes, so it can update the state and the view notifies the controller when some part of its view/state has changed and may be reflected in the model.
To this end, I would encourage you to define some kind of model, which is normally described by a interface which can be used by the various aspects of your program. Updates to the model don't need to come from the user/UI, but you will need to ensure that you clearly document when notifications might come from a different thread other than the Event Dispatching Thread, so your UI code can take correct actions and synchronise the updates.
So, based on you example, your model might have a method call setText (or some such), which triggers some kind of event notification to registered listeners.
This instance of the model would be shared amongst the various classes of your application
You main UI would be one of these classes listening for a change in the models state, when it detected a change, it would update its state accordingly.
This is an example of the observer pattern and you see this in use all over Swing (via it's listener/event API)
Originally I had the view holding commands for buttons, these buttons calculated this and output text onto JTextAreas after being pushed. What is produced is dependent on the value returned.
I am concerned I am not following standard MVC architecture by setting text like below inside my controller.
At the moment I changed my button commands into my controller as so
private class ReadActionListener implements ActionListener {
public void actionPerformed(ActionEvent l) {
/* there is other code in here, which results in setting text its not
just a set text button*/
/*interactions with model etc etc, outcome true? setText JTextArea like below*/
view.variable.setText("hi there");
}
}
Should I be setting text for the view inside the controller or is this breaking standard MVC architecture?
Thanks,
Jim
In MVC, you should not update the view from the controller. The controller is meant for event handling and altering the model according to these events. The model should then update its observers, ie. the view.
You can read up on the Observer design pattern here: http://javarevisited.blogspot.nl/2011/12/observer-design-pattern-java-example.html
There is a code example provided on that website as well.
In MVC, the model is a layer.
The model layer comprises of multiple objects: domain objects, services and mappers. You can read more in this post (although in PHP, the concepts still hold substance).
That being said, your controller handles the input from the user, sends this to the relevant object within the model layer, which then returns this data to the controller - and then your controller sends this to the view instance which handles the logic for displaying this to the user.
The observer pattern is really interesting and Koen's link above is a good one. I saved this snippet a while back from somewhere on SO:
Have state-setting operations on Subject call Notify after they change the
subject's state. The advantage of this approach is that clients don't have
to remember to call Notify on the subject. The disadvantage is that several
consecutive operations will cause several consecutive updates, which may be
inefficient.
Make clients responsible for calling Notify at the right time. The advantage
here is that the client can wait to trigger the update until after a series
of state changes has been made, thereby avoiding needless intermediate updates.
The disadvantage is that clients have an added responsibility to trigger the
update. That makes errors more likely, since clients might forget to call Notify.
This old but still valid example of the observer pattern may still be useful: http://javanook.tripod.com/patterns/observer.html
I would like to ask whether from a design pattern point of view whether it would be better to place listeners for GUI within the "view" or the "controller". A colleague believes that the "view" is the most natural place, but i'm not so sure.
If you are talking about Swing then, as previously discussed, MVC in Java is not a clear and simple as the pattern suggests. To answer your question, then, depends on how you define "view" and "controller" with respect to a specific application, and what you mean by "placing listeners" in one or the other.
I take the view the listeners are part of the controller mechanism - they provide a loose(ish) coupling between the view (that displays the current state) and the model (that maintains the current state), and provide a way for the two to interact. However, most Swing listeners are very tightly bound to UI events - mouse buttons being clicked, items being selected from lists, etc. - and so you may want to create an additional layer of abstraction which takes these UI events, which are captured by listeners, and translates them into something more general to the domain of your application. An EJB, for example, can provide a common interface for some business logic which may be triggered by a Swing UI or an API call via a web service. The controller, then, is the EJB, and the Swing event listener that triggers a call to that EJB is in the view.
In my current project we are using for our Swing client the following patterns:
Business Object (POJO) <--> (mapping) <--> Presentation Model (POJO with property change support) <--> (binding) <--> view components
Everything is fine and works the way we are expecting them to behave.
BUT, we encouter those problems when view begin to grow:
Many events are fired, resulting in cascading events. One update on a field may result in dozens of subsequent property update
When dialog complexity grows, the number of listeners grows as well, and the code begin to be messy and hard to understand.
Edit after first answer:
We don't fire event if there is no change on value.
We don't add listener if we have no need for them.
We have screen with very complexes rules and with a need for notification from other related panels. So we have a lots of useful listeners and a single user change can triggers many underlying events.
The idea about binding the presentation model with the business model is not so good for us: we perform some code in the mapping process.
I'm looking for guides, advices, best practices, etc about building maintainable Swing application, especially for the event management side.
There are many ways of reducing the number of events being sent.
Don't propagate an event when there is no change. A typical example for this one ios the idiomatic way of writing a setter triggering a PropertyChangeEvent (see below) but it is the case for all kind of events you fire by hand.
public void setMyField(Object newValue) {
Object oldValue = myField;
if((oldValue==null && newValue!=null) || (oldValue!=null && !oldValue.equals(newValue))) {
myField = newValue;
propertyChangeSupport.firePropertyChange("myField", oldValue, newValue);
}
}
}
Only register as event listener when you start to be interested in, and unregister as soon as you stop being interested in. Indeed, being a listener, even if it is for no action, forces the JVm to call the various methods used for event propagation. Not being a listener will avoid all those calls, and make the application by far simpler.
Consider replacing your POJO to increased POJO mapping by direct instanciation of increased POJO. or, to say things simpler : make your POJO authentical java beans with PropertyChangeEvent handling abilities. To allow them to be easily persisted, an easy solution is, once "rehydrated", or loaded from the persistence layer, add a persistence updater mechanism as PropertyChangeListener. This way, when a POJO is updated, the persistence layer gets notified, and updates the object in DB transparently.
All these are rather simple advices, requiring only a great dose of discpline, to ensure events are fired only at the right time, and for the right listeners.
I suggest a single event action per model. Don't try breaking it down to fields with the hopeless ProtpertyChangeListener. Use ChangeListener or your own equivalent. (Honestly, the event argument is not helpful.) Perhaps change the 'property' type to be a listenable object, rather than listening to the composite object.
The EventListenerList scheme used by most Swing components is fairly lightweight. Be sure to profile the code before deciding on a new architecture. In addition to the usual choices, another interesting approach to monitoring event traffic is suggested by this EventQueue subclass example.