Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Is there a collection of commonly-agreed-upon design guidelines for separating the Model classes from the View/Controller classes in a Java Swing app? I'm not so concerned that the View/Controller know nothing about the Model as the other way around: I'd like to design my Model to have no knowledge of anything in javax.swing. Ideally it should have a simple API enabling it to be driven by something as primitive as a CLI. It should be, loosely speaking, an "engine."

Communicating GUI events to the model isn't too hard -- the Action Performers can call the model's API. But what about when the model makes its own state changes that need to be reflected back to the GUI? That's what "listening" is for, but even "being listened to" is not entirely passive; it requires that the model know about adding a listener.

The particular problem that got me thinking involves a queue of Files. On the GUI side there's a DefaultListModel behind a JList, and there's some GUI stuff to choose files from the file system and add them to the JList. On the Model side, it wants to pull the files off the bottom of this "queue" (causing them to disappear from the JList) and process them in some way. In fact, the Model code is already written -- it currently maintains an ArrayList<File> and exposes a public add(File) method. But I'm at a loss as to how to get my Model working with the View/Controller without some heavy, Swing-specific modifications to the Model.

I'm very new to both Java and GUI programming, having always done "batch" and "back-end" programming up to now -- hence my interest in maintaining a strict division between model and UI, if it's possible and if it can be taught.

share|improve this question
    
    
Btw: In MVC the model should be decoupled from the view and the controller by default. You should read your textbook again, i think you haven't quite understood the concept. And you could implement a custom collection which notifies when it changes, much like .NET's INotifyCollectionChanged interface. –  Falcon Jul 14 '11 at 7:58
    
@Falcon: thanks for the links. Not sure I understand your comment, however.. "model should be decoupled from the view and the controller by default". Could you rephrase or elaborate? –  Chap Jul 14 '11 at 18:39

2 Answers 2

up vote 8 down vote accepted

There are no commonly-agreed-upon (i.e. defacto) design guidelines for MVC. It is not that entirely hard to do it yourself but requires some planning on your classes and lots of time and patience.

The reason there is no definite solution is because there are multiple ways to do MVC, all with their pros and cons. So just be smart about it and do what suits you the best.

To answer your question, you actually want to decouple the controller from the view as well (so you can use the same business rule logic for both a Swing app and in the console app). In the Swing example you want to decouple the controller from the JWindow and whatever widget in Swing. The way I used to do (before using actual frameworks) is to create an interface for the view that the controller uses:

public interface PersonView {
    void setPersons(Collection<Person> persons);
}

public class PersonController {

    private PersonView view;
    private PersonModel model;

    public PersonController(PersonView view, PersonModel model) {
        this.view = view;
        this.model = model;
    }
    // ... methods to affect the model etc. 
    // such as refreshing and sort:

    public void refresh() {
        this.view.setPersons(model.getAsList());
    }

    public void sortByName(boolean descending) {
       // do your sorting through the model.
       this.view.setPersons(model.getSortedByName());
    }

}

For this solution during startup you need to register the controller into the view.

public class PersonWindow extends JWindow implements PersonView {

    PersonController controller;
    Model model;

    // ... Constructor etc.

    public void initialize() {
        this.controller = new PersonController(this, this.model);

        // do all the other swing stuff

        this.controller.refresh();
    }

    public void setPersons(Collection<Person> persons) {
        // TODO: set the JList (in case that's you are using) 
        // to use the given parameter
    }

}

It might be a good idea to create an IoC-container to do all the setup for you instead.

Anyhow, this way you can implement console-only views, using the same controllers:

public class PersonConsole implements PersonView {

    PersonController controller;
    Model model;

    public static void main(String[] args) {
        new PersonConsole().run();
    }

    public void run() {
        this.model = createModel();
        this.controller = new PersonController(this, this.model);

        this.controller.refresh();
    }

    public void setPersons(Collection<Person> persons) {
        // just output the collection to the console

        StringBuffer output = new StringBuffer();
        for(Person p : persons) {
            output.append(String.format("%s%n", p.getName()));
        }

        System.out.println(output);
    }

    public void createModel() {
        // TODO: create this.model
    }

    // this could be expanded with simple console menu with keyboard
    // input and other console specific stuff

}    

The fun part is how to do event handling. I implemented this by letting the view register itself to the controller using an interface, this is done using the Observer pattern (if you're using .NET you'd be using event handlers instead). Here is an example of a simple "document observer", that signals when the a document has been saved or loaded.

public interface DocumentObserver {
    void onDocumentSave(DocModel saved);
    void onDocumentLoad(DocModel loaded);
}

// in your controller you implement register/unregister methods
private List<DocumentObserver> observers;

// register observer in to the controller
public void addObserver(DocumentObserver o) {
    this.observers.add(o);
}

// unregisters observer from the controller
public void removeObserver(DocumentObserver o) {
    this.observers.remove(o);
}

public saveDoc() {
    DocModel model = model.save();
    for (DocumentObserver o : observers) {
        o.onDocumentSave(model);
    }
}

public loadDoc(String path) {
    DocModel model = model.load(path);
    for (DocumentObserver o : observers) {
        o.onDocumentLoad(model);
    }        
}

That way, the view can properly update itself since it is subscribing to the document updates. All it has to do is to implement the DocumentObserver interface:

public class DocumentWindow extends JWindow 
        implements DocView, DocumentObserver {

    //... all swing stuff

    public void onDocumentSave(DocModel saved) {
        // No-op
    }

    public void onDocumentLoad(DocModel loaded) {
        // do what you need with the loaded model to the
        // swing components, or let the controller do it on
        // the view interface
    }

    // ...

}

I hope these motivating examples gives you some ideas on how to do it yourself. However I strongly advise you to consider using frameworks in Java that do most of the things for you, or else you'll end up having a lot of boilerplate code that takes a long time to write. There are a couple of Rich Client Platforms (RCP) that you could use that implement some of the basic functionality that you most likely need, such as application-wide document handling and a lot of basic event handling.

There are a couple I can think of from my head: Eclipse and Netbeans RCP's.

You still need to develop controllers and models for yourself, but that's why you use an ORM. Example would be Hibernate.

IoC containers are cool'n all, but there are frameworks for this as well. Such as Spring (which also does data handling as well among other things).

share|improve this answer
    
Thanks for taking the time to write such a long response. Most of it is a bit over my head at this point, but I'm sure Wikipedia will help. I am using both Eclipse and Netbeans, and leaning to the latter. I'm not sure how to distinguish the Controller from the View there, but your pre-framework example at the top helps. –  Chap Jul 14 '11 at 20:09

My take on this is that sometimes we need to compromise

As you say, it would be great if we could propagate change notification implicitly without the observed object having explicit infrastructure for this. For common imperative languages like Java, C#, C++ their runtime architecture is too lightweight, as of now, anyway. By that I mean it is not part of the language specification at this time.

In your particular case, I don't think it is exactly a bad thing to define/use some generic interface like INotifyPropertyChanged (as in c#), since that is not automatically coupled to a view anyway - it just says that if I change, I will tell you.

Again, I agree it would be great if we didn't have to define the change notification ourselves, but then again if it was implicit for all classes it might incur overhead.

share|improve this answer
    
the more I think about it, I realize you're right - the model object has to be involved to some extent in initiating notification to the GUI that a change has occurred; otherwise the GUI would have to poll the model to discover changes - and that's bad. –  Chap Jul 14 '11 at 18:46

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.