Swing e MVC

Estou seguindo este artigo para implementar MVC tradicional (perceba que não estou tentando implementar o estilo de MVC Apple Cocoa) em um aplicativo swing.

Baseado nas seguintes frases:

[quote]This section will take a closer look at one way to implement Figure 1 in the context of an application in the Java Platform, Standard Edition 6 (Java SE 6). Once the model, view, and controller objects are instantiated, the following occurs:

The view registers as a listener on the model. Any changes to the underlying data of the model immediately result in a broadcast change notification, which the view receives. This is an example of the push model described earlier. Note that the model is not aware of the view or the controller -- it simply broadcasts change notifications to all interested listeners.
The controller is bound to the view. This typically means that any user actions that are performed on the view will invoke a registered listener method in the controller class.
The controller is given a reference to the underlying model.

Once a user interacts with the view, the following actions occur:

The view recognizes that a GUI action -- for example, pushing a button or dragging a scroll bar -- has occurred, using a listener method that is registered to be called when such an action occurs.
The view calls the appropriate method on the controller.
The controller accesses the model, possibly updating it in a way appropriate to the user's action.
If the model has been altered, it notifies interested listeners, such as the view, of the change. In some architectures, the controller may also be responsible for updating the view. This is common in Java technology-based enterprise applications.

[/quote]

Implementei o seguinte código:
Model.java[code]package mvc.model;

import java.util.Observable;

public class Model extends Observable {

private int counter;

public Model() {
    counter = 0;
}

public void count() {
    counter += 1;
    setChanged();
    notifyObservers();
}

public int getCounterValue() {
    return counter;
}

}[/code]
View.java[code]package mvc.view;

import java.util.Observable;
import java.util.Observer;
import mvc.controller.Controller;
import mvc.model.Model;

public class View extends javax.swing.JFrame implements Observer {

private Controller controller;

public View() {
    initComponents();
    // Onde instanciar o controller?
    // Código acoplado! :(
    controller = new Controller(this);
}

/**
 * This method is called from within the constructor to initialize the form.
 * WARNING: Do NOT modify this code. The content of this method is always
 * regenerated by the Form Editor.
 */
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">                          
private void initComponents() {

    buttonDoIt = new javax.swing.JButton();
    labelCount = new javax.swing.JLabel();

    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

    buttonDoIt.setText("Do It!");
    buttonDoIt.addActionListener(new java.awt.event.ActionListener() {
        public void actionPerformed(java.awt.event.ActionEvent evt) {
            buttonDoItActionPerformed(evt);
        }
    });

    labelCount.setText("0");

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addGap(23, 23, 23)
            .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                .addComponent(buttonDoIt)
                .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                    .addComponent(labelCount)
                    .addGap(20, 20, 20)))
            .addContainerGap(23, Short.MAX_VALUE))
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addComponent(labelCount)
            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
            .addComponent(buttonDoIt)
            .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
    );

    pack();
}// </editor-fold>                        

private void buttonDoItActionPerformed(java.awt.event.ActionEvent evt) {                                           
    controller.count();
}                                          

/**
 * @param args the command line arguments
 */
public static void main(String args[]) {
    /*
     * Set the Nimbus look and feel
     */
    //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
    /*
     * If Nimbus (introduced in Java SE 6) is not available, stay with the
     * default look and feel. For details see
     * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
     */
    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Nimbus".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException ex) {
        java.util.logging.Logger.getLogger(View.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
        java.util.logging.Logger.getLogger(View.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
        java.util.logging.Logger.getLogger(View.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(View.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    //</editor-fold>

    /*
     * Create and display the form
     */
    java.awt.EventQueue.invokeLater(new Runnable() {

        @Override
        public void run() {
            new View().setVisible(true);
        }
    });
}
// Variables declaration - do not modify                     
private javax.swing.JButton buttonDoIt;
private javax.swing.JLabel labelCount;
// End of variables declaration                   

@Override
public void update(Observable o, Object o1) {
    String value = Integer.toString(((Model) o).getCounterValue());
    labelCount.setText(value);
}

}[/code]
Controller.java[code]
package mvc.controller;

import mvc.model.Model;
import mvc.view.View;

public class Controller {

private Model model;

public Controller(View view) {
    model = new Model(); // Onde deve ficar?
    model.addObserver(view);
}

public void count() {
    model.count();
}

}[/code]
Cada vez que o usuário clica em um botão, um label é atualizado, exibindo um valor que está no Model (valor += 1).

Tenho as seguintes dúvidas:

1 - O MVC tradicional está corretamente implementado?
2 - O código está totalmente acoplado. Onde eu deveria instanciar cada elemento do MVC?
3 - Esta aplicação é simples. Tem apenas um JFrame. Como as instâncias são criadas em aplicações mais complexas, com vários frames?

Sou iniciante em Java mas programo em outra linguagem de programação. Aceito qualquer sugestão para melhorar o código e entender o conceito do MVC tradicional (estou tentando seguir ele a risca, apenas para fins didáticos). Se você tiver exemplos dessa ou outras arquiteturas, por favor, compartilhe.

Peço perdão se não postei no fórum correto.
Valeu.

veja isto: http://mballem.wordpress.com/2011/02/21/utilizando-swing-com-banco-de-dados/

vc deveria ter postado no forum: “Interface Gráfica”, mas depois algum moderador muda isso, eu acho !

segue o link q mandei, e um bom exemplo pra ti começar.

t+ e boa sorte.

Ou em Arquitetura :slight_smile:
Realmente, fiquei confuso na hora de postar.

Vou ler o link, volto para comentar a respeito.

Obrigado.

Acabei de ler o link, bem interessante.

Algumas considerações:

1 - Não entendi porque ele cria uma instância do controller a cada ação do usuário na GUI (evento).
2 - Achei bem KISS. O controller requisita informações do Model, o mesmo retorna para o Controller, que, por consequência, retorna para a View, no evento chamado.
3 - Continua um pouco acoplado, as instâncias são criadas dentro das classes. É normal esse acoplamento?

Teria que ver como isso fica com outras telas. Se eu tivesse um tela principal. Ao clicar em um botão abriria uma segunda. A View cuidaria de chamar a outra ou um Controller faria isso? Consigo entender que as ações que lidam com o Model na tela nova vão chamar um Controller, que chamará um Model.

Alguém tem outros exemplos de implementação? Um exemplo mais fiel ao MVC tradicional talvez …

Obrigadão, foi muito útil.

[quote=proveyourself]Acabei de ler o link, bem interessante.

Algumas considerações:

1 - Não entendi porque ele cria uma instância do controller a cada ação do usuário na GUI (evento).
2 - Achei bem KISS. O controller requisita informações do Model, o mesmo retorna para o Controller, que, por consequência, retorna para a View, no evento chamado.
3 - Continua um pouco acoplado, as instâncias são criadas dentro das classes. É normal esse acoplamento?

Teria que ver como isso fica com outras telas. Se eu tivesse um tela principal. Ao clicar em um botão abriria uma segunda. A View cuidaria de chamar a outra ou um Controller faria isso? Consigo entender que as ações que lidam com o Model na tela nova vão chamar um Controller, que chamará um Model.

Alguém tem outros exemplos de implementação? Um exemplo mais fiel ao MVC tradicional talvez …

Obrigadão, foi muito útil.[/quote]

Como assim um exemplo mais fiel ao MVC ??? Para os padroes MVC(model - view - controller) este esta de muito bom tamanho. Sobre acoplamento, realmente nao os vejo. Eu trabalho da seguinte maneira.

Model - Classes de Negocio
View - Meus JFrame/JDialog/JInternalFrame
Controller - Meus DAO de persistencia.

Na real, pela maneira a q se propoe o MVC o exemplo esta até msm mais organizado do q muitos q ja vi por ai, sempre uso ele de referencia para os “novato” q perguntam sobre MVC nos posts do forum, alias se der uma pesquisada no forum vai achar mais de 1milhao de posts sobre isso.

t+ e boa sorte.

O artigo da Oracle, que postei acima, cita dois exemplos. Um é o MVC tradicional e outro é o MVC Apple Cocoa like … O tradicional parece usar Observer/Observable. O da Apple não li inteiro, vou fazer.

Com certeza, está de bom tamanho. Eu só tenho aquelas dúvidas mesmo, a intenção não é criticar, mas sim, entender.

Acoplado porque a View instancia um Controller. O Controller instancia o Model. O Model é o menos acoplado, não conhece a View nem o Controller. É assim que deveria ser? Desacoplar apenas o Model?

Vou pesquisar sim.

Obrigado, você tem ajudado bastante!

Achei um comentário interessante neste link.

[quote]The problem is that the song is NOT about Smalltalk MVC. In this song, the controller is a layer between the view and the model, which usually means it is a mediator. The song also says that the controller is copying values from one field to another, which also indicates that it is a mediator. However, in true MVC, the controller is a strategy for handling events. The events come directly to it, rather than to the view. The controller changes the model, but it is not notified by the model. When the user presses a key or moves the mouse, the controller receives the event. It checks with the view to map mouse locations into model coordinates, then interacts directly with the model. If it changes the model then the model notifies all dependents (observers), which notifes the view, which redisplays.

The song desribes Ivar Jacobson’s Model/Interface/Control, in which the Control is responsible for an entire use case. It is not MVC. Jacobson’s model is like the MVC model, but his Interface is a combination of View and Controller and his Control is not at all like
a real Controller.[/quote]
Parece que o Controller lida diretamente com os eventos no MVC tradicional (Smalltak). Lembro ter lido isso no paper do autor do MVC. Só não consigo entender aquilo tudo porque é muito técnico para o meu conhecimento limitado e está em Smalltalk.

Valeu.