From: Lew on
markspace wrote:
> Normally, the Controller has references to the View and the Model, not
> the other way around.
>
> public class Controller {
>
> View view;
> Model model;

More commonly the controller could have a collection of model classes or
instances and map of {model instance, outcome} -> {view instance} entries.

There would also be a map of {view result} -> {model instance} entries.

A framework like Struts or JSF can build the maps at deployment time.


> (Note this controller now likely needs to be
> synchronized and created on the EDT.)

The controller should definitely not run on the EDT. It or (preferably) the
view components it invokes should use 'invokeAndWait()'.

I agree with the bulk of your comments, however.

> You may need lots of
> controllers to implement a single window if that window has lots of
> buttons or controls.

There are various MVC paradigms. The simple "Model 2" version (for example,
Struts) has a single front controller. More fractal versions such as JSF do
what you suggest, having multiple controllers.

> Views should be "dumb" and just fire events. Don't keep any state in a
> view, other than the state it already has (like the text string in a
> JTextField).

The view may also handle surface edits and other view logic to ensure that
data that reach the controller(s) from the view are consistent.

> In classic MVC, the model updates the view via a call back, and the view
> has a reference to the model. However, Java uses a "split model" design

I consider "classic" the MVC paradigm that is, as you say, procedural and the
controller loop looks something like:

public void control()
{
for ( View view = initialView(); view != BYEBYE;)
{
Request request = view.getRequest();
Model model = chooseModel( request );
Result result = model.process( request );
view = nextView( model, result );
}
}

where 'chooseModel()' and 'nextView()' are methods in the controller and
'View' and 'Model' are interfaces with a 'getRequest()' and 'process()'
method, respectively.

When I've written Model 2 code by hand, the controller is only a couple of
hundred lines long, and most of that comprises the setup code for the maps.

> where views (JComponents) have their own model. So I think it's kind of
> a toss up how your model updates the view when needed. I'd be inclined
> to have it go through the Controller too, meaning no direct linkage.

Exactly so.

--
Lew
From: markspace on
Lew wrote:

> markspace wrote:
public Controller ( View view, Model model ) {
this.view = view;
this.model = model;

this.view.addLoadFileActionListener( new ActionListener() {
@Override
public actionPerformed( final ActionEvent e ) {
loadFile( e );
}
}
>> (Note this controller now likely needs to be synchronized and created
>> on the EDT.)

>
> The controller should definitely not run on the EDT. It or (preferably)
> the view components it invokes should use 'invokeAndWait()'.


What I was looking at there was a this-escape. The anonymous
ActionListener I create there has an implicit this pointer that is
passed to the view, probably a JComponent, which can then fire events
asynchronously. Creating the Controller by calling the constructor on
the EDT would alleviate the asynchronous calling part, although the
this-escape still isn't great. It's basically a coding boo-boo I didn't
have time to fix.

Regardless of the this-escape, I think actionListeners (or their
equivalents) should be created and installed on the EDT, to prevent them
from firing asynchronously before the rest of the GUI is built.

>
> I consider "classic" the MVC paradigm that is, as you say, procedural
> and the controller loop looks something like:


Pretty much everything I know about other MVC patterns comes from Martin
Fowler's white paper on the subject:

<http://www.martinfowler.com/eaaDev/uiArchs.html>

From: Lew on
markspace wrote:
> Regardless of the this-escape, I think actionListeners (or their
> equivalents) should be created and installed on the EDT, to prevent them
> from firing asynchronously before the rest of the GUI is built.

Yes, absolutely.

A proper Controller will not define the listeners per se, but pick up the
result (what I called a "Request" in my mini-example upthread) from a view
component (such as Strut's 'ActionForm') method call. For a Swing view, that
view component will handle the inter-thread communication so that any
listeners will live on the EDT but the view component will return a request to
the controller off the EDT.

If the controller is aware of Swing, it's not proper separation between the
view and the controller.

--
Lew
From: Daniel Pitts on
On 2/17/2010 1:39 PM, Lew wrote:
> markspace wrote:
>> Regardless of the this-escape, I think actionListeners (or their
>> equivalents) should be created and installed on the EDT, to prevent
>> them from firing asynchronously before the rest of the GUI is built.
>
> Yes, absolutely.
>
> A proper Controller will not define the listeners per se, but pick up
> the result (what I called a "Request" in my mini-example upthread) from
> a view component (such as Strut's 'ActionForm') method call. For a Swing
> view, that view component will handle the inter-thread communication so
> that any listeners will live on the EDT but the view component will
> return a request to the controller off the EDT.
>
> If the controller is aware of Swing, it's not proper separation between
> the view and the controller.
>
I think you've topsy-turvied your concepts here. Controllers know the
details of what it is controlling. In a pure design:

The Controller would know whether to put something on the EDT or not.
The View doesn't know about specific controllers or models.
The Model doesn't know about sepcific controllers or views.
The Controller "connects" the view and model to each-other through
generic interfaces.

--
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
From: RedGrittyBrick on
On 17/02/2010 17:15, Fencer wrote:
> I will read some more and try to make a concept implementation. Just one
> question, if the view (a JPanel in my case) doesn't know about the
> controller but the controller knows about the view, how should I
> implement my button listener? Right now it's an anonymous inner class to
> the JPanel-extended class, I don't get how to handle that and not have
> the view know the controller?


There is no single correct way to implement MVC. This may not be right -
it's just answering your question as stated and in isolation.

interface ListenableView {
void addListener(Listener l);
...
}

class FooView implements ListenableView {
...
void addListener(Listener listener) {
fooButton.addListener(listener);
}
}

class BarController implements Listener {
...
someMethod(...) {
...
aListenableView.addListener(this)
}
}