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.