Win a copy of Java Persistence with Spring Data and Hibernate this week in the Spring forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Ron McLeod
  • Tim Cooke
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • Junilu Lacar
  • Rob Spoor
  • Jeanne Boyarsky
Saloon Keepers:
  • Stephan van Hulst
  • Carey Brown
  • Tim Holloway
  • Piet Souris
Bartenders:

Still having some trouble with Observer/Observable

 
Ranch Hand
Posts: 262
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I've tried to implement some observers and observables and discovered that when some requirements changed, my classes didn't hold up well. So I'm concerned I'm understanding the concept correctly. I also started reading more about model-view-controller and while in isolation that makes sense, I think what I did was implement observation = model and observer = view-controller. Which made sense at the time, but got confusing when some GUI elements updated observations and used them.

I'm trying to get a 'feel' for how things fit together, so excuse me if I don't have a short code snippet.

Let's say I have something like this-

Panel 1- A table that displays a,b,c,d where d is computed from several rows that all contain the same a,b
Panel 2- A table that displays only one instance of each unique a,b and also the value e, which is computed from all the c's and d's that have the same a,b

What I thought was that I would let the tables models of the tables in the Panels keep track of the 'raw' data. But I would also have an Observable that maintained the computed results, since both tables needed to access them.

I was going to create an object that had (a,b) as a key and Panel 1 would update the observable with a new object when a cell changed. But then there is the question of d. Should my Panel class calculate d and include it as part of the update of the observable? Or would it be better to let the Observable calculate the value and then report the new value back to Panel1 (acting as an observer).

Panel 2 does not contain anything the user can enter. So I was planning that it would be an Observer. When Panel 1 updates the (a,b) object, Panel 2 is informed and updates the table. However, again, a new value needs to be computed. That in the end will be used by yet another panel Panel 3, so cannot be kept just locally in Panel 2. So should Panel 2 calculate this new value and pass it back to the Observable? Or should the Observable calculate the value, so it is available when Panel 2 is notified of a data change? Or should I make yet another Observable. My concern there is that I think I would end up with four or more Observables that would need to be passed to various Observers and then I am not sure how to keep the order of operations in synch.

One thing that gets me confused is the updates, i.e.

Panel 1 gets user data, calculates d, sets new observable data
Panel 2 gets update, updates its view, calculates new data, sets new observable data, oops, now Observable is telling it there is new data again- the data it just put in.

but the alternate

Panel 1 gets user data, sets new observable data, observation calculates d, Panel 1 is informed that new data is available, but hopefully doesn't tell the observation
Panel 2 gets update, observation has already calculated all the computable numbers, so Panel 2 updates it's view

seems to violate the way observer/observable is supposed to be used. In 'real' life I also find it's easy to end up with situation where the constructor of some of these panels has a whole laundry list of parameters so that the updates and setting of observations gets done.

Can anyone give me a better conceptual understanding of how these interactions are supposed to be organized?
 
Ranch Hand
Posts: 808
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There are many different flavors of Model-View-Controller, but they all have the same goal of separating the concerns of decision making, managing state, and user interaction. Better still if we can avoid any situation where the model and view are dependent on each other. The MVC flavor I like best, and use when the choice is left to me, is the one identified by Martin Fowler as Passive View. Here the controller is the only observer. It watches everything and makes all the decisions. It knows that if the model is being updated because of a change in the View, the view does not need to be redundantly updated, and vice versa.

Jon Swanson wrote:Panel 1 gets user data, calculates d, sets new observable data
Panel 2 gets update, updates its view, calculates new data, sets new observable data, oops, now Observable is telling it there is new data again- the data it just put in.



You are giving your Panels too much responsibility. View components should display data and take user input. They shouldn't do anything else. Calculations should be performed in the model or by the controller. There are differing schools of thought about what a model should be. Some people prefer a model to be an object with attributes, getters and setters, and no other methods. With this kind of model, all logic would be performed by the controller. Another way to organize things is to keep logic in the model as well; with this design the model is a little community of related objects, together with the methods that are needed to use them together.

Here's how I think your scenario ought to look:

Panel 1 gets user data.
Controller is notified of the change.
Controller gets the values from the table.
Controller updates the model.
Model calculates d.
Controller gets d from the model.
Model calculates values for Panel 2.
Controller updates Panel 1 and Panel 2.

The thing to notice here is how the controller is doing the heavy lifting, and the view and model just do what they are told.

 
Jon Swanson
Ranch Hand
Posts: 262
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks Dennis, that was very helpful.

Could we continue this discussion for a little bit to help me cement some of these concepts. I am still having a little trouble making the leap from an understanding at the level of examples and actually implementing something that meets requirements which can be a bit dodgy.

Eventually, the GUI will have 8 tables, 2 purely display computed data, 5 mostly just accept user input (though there are constraints on the input that are defined by computed values) and one that does both. There are also assorted text fields, check boxes, radio buttons and so on that modify the behavior of the computation. But for this discussion I think it is sufficient to divide the world into 8 panels and not worry too much about what is in them, just accept the idea that some need model data to validate input and some display model data the user does not input, but is computed.

Then there are 4 graphs. You'd think they would be purely output, but two of them have elements that require results to be recalculated and then propagated back to a couple of the tables.

I am using tabbed panes to make the GUI less busy. There are 5 sections that are displayed at the same time (out of 12 total).

My main is very simple, basically

MyGUI()
mb = new MyMenubar();
p1 = new MyPanel1();
p2 = new MyPanel2();
add(p1);
add(p2);

So it doesn't actually know the reference of the tables. It just organizes the layout of the main elements. I have other classes that build the specific Panel and arrange all the GUI objects of the specific panel. Each of the Panel1, Panel2, ... have distinct functions and if it weren't for the fact that some need to use data from other panels, the design would be quite simple and I wouldn't be posting these questions.

So I may have a class that does this sort of thing

MyPanel1()
t1 = new JTable();
b1 = new JButton();
add(t1);
add(b1);

To update the Table, the controller would need to know about t1 and anything else that would get it's value changed.

Dumb question 1: How do you actually insert the controller? With the observer/observable I would register the observer and provide update functions in my panel classes (and pass in a reference if the data needed an update).

MyGUI()
mb = new MyMenubar();
mo = new MyObservableValue();
p1 = new MyPanel1(mo);
p2 = new MyPanel2();
mo.addObserver(p1);
add(p1);
add(p2);

MyPanel1(MyObservableValue myObservable) implements Observer
t1 = new JTable();
b1 = new JButton();
add(t1);
add(b1);

public void update(Observable obs, Object obj) {stuff}

class MyListener implements TableModelListener
{ myObservable.setStuff() }

In this way if thinking, the views handle updating themselves, then all the update code is right there with the code that creates the view. The thing that gives me trouble implementing this is when one Panel needs to setStuff and update, not just one or the other. I've been trying to handle that by passing an enum when I run notifyObservers to let the different observers know 1) do they need to do anything and 2) what they need to do. As you say, I give the panels a lot of responsibility to create whatever they need from MyObservableValue.

So now I think I want to turn this on its head to use a controller. I am I headed in the right direction?

MyGUI()
mb = new MyMenubar();
mc = new MyController();
p1 = new MyPanel1(mc);
p2 = new MyPanel2();
mc.addView(p1);
add(p1);
add(p2);

MyPanel1(MyController mc)
t1 = new JTable();
b1 = new JButton();
add(t1);
add(b1);

class MyListener implements TableModelListener
{ mc.updatePanel1Data() }

MyController()

MyPanel1 panel1;
MyPanel2 panel2;

model = new MyDataModel();

public void setPanel1( MyPanel1 p )
{ panel1 = p }

public void updatePanel1Data(Object o)
{
model.setPanel1Data(o);
computePanel1Data();
setPanel1Data();
}

private computePanel1Data()
{
a = model.getA();
b = model.getB();
n = something(a, b);
model.setN(n);
}

private void setPanel1Data()
{
n = model.getN();
panel1.getTable().getModel().setValueAt(i, j, n);
}

public void setPanel2Data(Object o) {}


or not, since every object has its own set of stuff that must be modified, wouldn't I need to hard-code all that in the controller? So if I changed a field in the view, I'd need to change the command in the controller? I was just looking at an MVC example where the controller implemented the action listeners, but all the code that modified the data was in the model and the controller was full of model.setXXX(), model.doXXX(), model.getXXX(), view.setXXX(). Which seems a lot more straightforward with one view than with twelve. I also got a little lost when I tried to extend setting action listeners in the controller to setting item listeners and all the other listeners that might need to be handled by the controller. I believe you are suggesting the doXXX() should be in the controller? Should the setXXX() be in the controller also? I guess to me I feel like I am reverting back to monolithic code where practically everything is done in one place and just dumped out to store or view the data. So I'm not sure I have the concept.



 
I love a good mentalist. And so does this tiny ad:
The Low Tech Laboratory Movie Kickstarter is LIVE NOW!
https://www.kickstarter.com/projects/paulwheaton/low-tech
reply
    Bookmark Topic Watch Topic
  • New Topic