Dúvida com MVC

Boa tarde pessoal,

Estou começando em Java e quebrando a cabeça pra entender onde colocar cada coisa, considerando uma abordagem MVC.

Sendo assim, suponha que seja requerida uma interface com o usuário com botões de navegação do tipo “Primeiro”, “Próximo”, “Anterior” e “Ultimo”.

Eu criei a interface grafica (esse seria meu componente View ?) que utiliza um objeto do tipo Usuario e seta cada JTextField com o valor do atributo correspondete do objeto, esse valor do é acessado através de um método getXXXX (esse objeto Usuário seria meu Controller ?).

Bom, se eu não estiver falando muito bobagem e esquecenco do Model por enquanto tudo parece bem. Agora o dúvida:

Considerando que cada um dos meus botões de navegação, “Primeiro”, “Próximo”, “Anterior” e “Ultimo”, possuem um método do tipo:

 private void btPrimeiroActionPerformed(java.awt.event.ActionEvent evt) {                                           
 //Esse médoto deveria retornar ou atualizar a interface com o primeiro 
 //elemento da tabela Usuario
 
  }                                     
 

O que devo colocar nesse método para que, mantendo a estrutura MVC, eu retorne respectivamente o primeiro, próximo, anterior e último elemento da minha tabela ?

Eu deveria alterar minha View para receber um array de Usuário no lugar de um Objeto ?

Será que alguem vai entender a minha dúvida ?!

É que sou meio enrolado mesmo…

De qualquer forma, obrigado.

Um abraço a todos

Bem no conceito de mvc, o model, é quem trabalha diretamente com o negócio, ou seja, provavelmente a clase “Usuario” faz parte do model, o que eu estou sentindo falta é de uma parte intermediária, que justamente seria o controller. é uma parte do seu softweare que faz a comunicação entre a interface e as classes de negócio, pra deixar as classes de negócio independentes.

mOska:

Model não é a camada responsável pela persistencia dos dados ? Ou seja, não é onde vamos colocar a conexão com o banco, insert´s, delete’s, etc ?

As regras de negócio, ou seja, validação de dados digitados pelo usuário, não é o papel do Controller ?

Mas no caso da minha questão: que código colocaria no método
private void btAnteriorActionPerformed(java.awt.event.ActionEvent evt)
para que ao clicar no botão os dados apresentados na tela sejam atualizados corretamente ?

Obrigado.

Um abraço,

Olá.

Está havendo uma certa confusão de conceitos. A camada de persistência não é prevista pela arquitetura MVC. Apenas modele-a como uma quarta camada, que conhece o modelo, mas não tem conhecimento do controller ou da view.

No Model, represente o seu sistema. Os componentes. Seus problemas. A “inteligência” do seu sistema, que resolve esses problemas. No MVC clássico, esse model deve ser “observável” pela interface, que por sua vez deve ser capaz de se atualizar (http://en.wikipedia.org/wiki/Observer_pattern).

A validação dos dados pode ser papel do Controller, mas muitas vezes vai exigir colaboração do Model (exemplo: como saber se já existe um usuário cadastrado com determinado e-mail?).

Mais leitura:
http://fragmental.com.br/wiki/index.php?title=MVC_e_Camadas

Enfim, um pouco de prática.

Pela breve descrição do teu problema, imagino que no modelo haja duas classes. Uma classe Usuario, e uma outra, que mantém uma lista ordenada de objetos Usuario e uma referencia ao “atual” (e que tem também os metodos e a lógica para retornar proximo, ultimo, anterior, primeiro).

Na arquitetura proposta pelo swing, deverias usar subclasses de javax.swing.Action para cada ação (“proximo”, “anterior” etc) e fazer uso delas na camada de apresentação (“view”, a janela do programa). Segue código exemplo.

Model class Model extends Observable { private Usuario atual; private List<Usuario> list; public Usuario proximo() {} public Usuario anterior() {} public Usuario atual() {} ... public void setUsuario(Usuario u) { ... setChanged(); notifyObservers(); } }

Controller [code]
public class ProximoAction extends AbstractAction implements Action {
private Model model;

public ProximoAction(Model m) {…}

public void actionPerformed(ActionEvent evt) {
model.setUsuario(model.proximo()); //gera um evento na interface
}
}[/code]

View [code]
public class View extends JFrame {
private Model model;

public View (Model m) {
this.model = m;
model.addObserver(this); //registra-se como “observador”
}

public void construirJanela() {
jButtonProximo = new JButton();
jButtonProximo.setAction(new ProximoAction(this.model)); //instancia o controller
}

public void update(Observable obs, Object obj) {
//mudou o usuario ‘atual’ do modelo
//atualizar campos na tela usando dados do usuario atual
Usuario u = this.model.atual();
}
}[/code]

Note que este approach é bem simplista, e dificilmente seria suficiente para sistemas maiores e mais complexos. E eu nem fiz a camada de persistência.
Podem ser necessários eventos e listeners mais especializados, pode ser necessário que a própria camada de apresentação mantenha um estado (http://www.martinfowler.com/eaaDev/PresentationModel.html).

Pode-se optar por responsabilizar o controller pela atualização da camada de apresentação. Pode-se usar algum framework para fazer “binding” automático (https://binding.dev.java.net/ - https://genesis.dev.java.net/).

Mas… bom… não vou escrever um livro. Não aqui, agora. :smiley:

[]s
Bruno

bzanchet:

Desculpe pelo abuso, mas se puder me explicar mais algumas coisas…

Eu estou no começo do começo… então nunca nem tinha ouvido falar nas interfaces Observer e Action que vc citou, então, sinceramente, não consegui entender o que esta acontecendo no seu exemplo.

Meu pedido é: da pra implementar um modelo MVC sem utilizar essas interfaces e classes que vc citou ?
Explicando melhor:
Eu criei basicamente 3 classes, sendo:
-Uma classe CadastroUsuario, que é a minha tela, com todos os JTextFields e JButtons que vou utilizar.

-Uma classe Usuario, que possui todos os atributos de um usuário e getters e setters para acessá-los.

-Uma classe UsuarioDAO que possui um método Conecta(), que cria a conexão com o Banco de Dados, um método BuscaUsuario(int userID) que faz um select no banco pelo ID do usuario e retorna um objeto Usuario.

Como a coisa esta funcionando, ou seria melhor dizer, como não esta funcionando…

Executo a classe CadastroUsuario, que no seu construtor utiliza o método BuscaUsuario da classe UsuarioDao para receber um Usuario e mostra esses dados na tela.

Pra mim parece obvio que esta errado, porque:
-eu não tenho uma lista encadeada de usuarios,
-cada vez que quero mostrar outro usuario, clicando em proximo, por exemplo, eu chamo novamente o método BuscaDados da classe UsuarioDAO, o que leva a uma nova conexão com o banco e um novo select.
-a minha classe CadastroUsuario, que é a minha View (pelo menos eu acho que seja) esta utilizando a classe UsuarioDAO, o que não deveria acontecer num modelo MVC, certo ?

Só que entre saber que esta errado e como é o certo, pra mim esta uma grande distancia… será que voce pode me ajudar ?

Só mais uma questão… eu devo criar uma outra classe que irá utilizar a classe UsuarioDAO e criar uma lista de usuarios que será devolvida para a CadastroUsuario ?

Muito obrigado pela paciencia.

Um abraço.

Sim, é possível fazer uma aplicação MVC sem usar interface alguma. São só objetos, afinal.

Desculpa, mas infelizmente acho que as demais dúvidas são muito pouco específicas, nada que eu consiga responder de forma objetiva.

Meu conselho é: esqueça o padrão DAO, por enquanto. Tente entender, terminar a implementação (e até modificar) o exemplo que eu escrevi (um debugger ajuda, e modificações foram sugeridas aqui). E depois, leia sobre o DAO e tente incluí-lo no exemplo.

Se não quiser o que eu disse, tudo bem. Porém, poste aqui a implementação que fizesses, e faça perguntas mais específicas. Aí, sim, poderei ajudar.

Abraço,
Bruno

Bruno:

Vou tentar reproduzir a forma como acabei implementando e se você puder analisar e apontar onde estão os erros na abordagem vou ficar muito agradecido.

Primeiro a minha Interface com o usuario, suponho que seria minha View:

package app;

import java.util.List;

public class CadastroUsuario_2 extends javax.swing.JFrame {
    private Usuario user;
    //private List <Usuario> userLista;
    private UsuarioModel userModel = new UsuarioModel();
    
    /** Creates new form CadastroUsuario */
    public CadastroUsuario_2() {
        initComponents();
        user = userModel.atual();
        MostraDados(user);
    }
    
    private void MostraDados(Usuario u) {
        txtus_usID.setText(String.valueOf(u.getUsusId()));
        txtus_usLogin.setText(u.getUsusLogin());
        txtus_usNome.setText(u.getUsusNome());
        txtus_pePerfil.setText(u.getUspePerfil());
    }

    private void btAnteriorActionPerformed(java.awt.event.ActionEvent evt) {                                           
        user = userModel.anterior();
        MostraDados(user);
    }                                          

    private void btProximoActionPerformed(java.awt.event.ActionEvent evt) {                                          
        user = userModel.proximo();
        MostraDados(user);
    }                                         

  public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new CadastroUsuario_2().setVisible(true);
            }
        });
    }
    
     
}

Agora a minha classe Usuario (não sei como classifica-la, acredito que faça parte da camada Model):

package app;

@Entity
@Table(name = "usuario")
@NamedQueries( {
        @NamedQuery(name = "Usuario.findByUsusId", query = "SELECT u FROM Usuario u WHERE u.ususId = :ususId"),
        @NamedQuery(name = "Usuario.findByUsusLogin", query = "SELECT u FROM Usuario u WHERE u.ususLogin = :ususLogin"),
        @NamedQuery(name = "Usuario.findByUsusPassoword", query = "SELECT u FROM Usuario u WHERE u.ususPassoword = :ususPassoword"),
        @NamedQuery(name = "Usuario.findByUsusNome", query = "SELECT u FROM Usuario u WHERE u.ususNome = :ususNome"),
        @NamedQuery(name = "Usuario.findByUspePerfil", query = "SELECT u FROM Usuario u WHERE u.uspePerfil = :uspePerfil")
    })
    
public class Usuario implements Serializable {

    @Id
    @Column(name = "us_usId", nullable = false)
    private Integer ususId;

    @Column(name = "us_usLogin")
    private String ususLogin;

    @Column(name = "us_usPassoword")
    private String ususPassoword;

    @Column(name = "us_usNome")
    private String ususNome;

    @Column(name = "us_pePerfil")
    private String uspePerfil;
    
    /** Creates a new instance of Usuario */
    public Usuario() {     
    }
    
    /**
     * Cria uma nova instância de Usuario com os valores especificados.
     * @param ususId o ususId do Usuario
     */
    public Usuario(Integer ususId) {       
        Usuario userTemp = UsuarioDAO.BuscarUsuario(ususId);
        this.ususId = userTemp.getUsusId();
        this.ususLogin = userTemp.getUsusLogin();
        this.ususNome = userTemp.getUsusNome();
        this.uspePerfil = userTemp.getUspePerfil();
        this.ususPassoword = userTemp.getUsusPassoword();        
    }
        
    public Integer getUsusId() {
        return this.ususId;
    }

    public void setUsusId(Integer ususId) {
        this.ususId = ususId;
    }

    public String getUsusLogin() {
        return this.ususLogin;
    }

    public void setUsusLogin(String ususLogin) {
        this.ususLogin = ususLogin;
    }

/* Todos os outros getters e setters estariam aqui

    /**
     * Retorna um valor de código hash para o objeto.  Esta implementação computa
     * um valor de código hash baseado nos campos id deste objeto.
     * @return um valor de código hash para este objeto.
     */
    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.ususId != null ? this.ususId.hashCode() : 0);
        return hash;
    }
}

Agora a classe que chamei de UsuarioModel, mas agora não sei se ela representa esta camada:


package app;

import java.util.List;
import javax.swing.JOptionPane;

public class UsuarioModel {
    private Usuario userAtual;
    private List <Usuario> listaUser = null;
    
    
    /** Creates a new instance of UsuarioModel */
    public UsuarioModel() {
        listaUser = UsuarioDAO.BuscarListaUsuario();        
        userAtual = listaUser.get(0);
    }
    
    public Usuario proximo() {    
        
        if (listaUser.indexOf(userAtual) <  listaUser.size() - 1)
            userAtual = listaUser.get(listaUser.indexOf(userAtual)+1);  
        else
            JOptionPane.showMessageDialog(null, "Ultimo");
            
        return userAtual;
    }
    
    public Usuario anterior() {    
        if (listaUser.indexOf(userAtual) >  0)
            userAtual = listaUser.get(listaUser.indexOf(userAtual)-1);        
        return userAtual;
    }
    
    public Usuario atual() {    
        return userAtual;
    }    
}

E por fim uma classe responsável pela conexão com o banco, é nessa classe que eu pretendo colocar os métodos de persistencia, insert, update e delete, alem do select que ja coloquei:

package app;

public class UsuarioDAO {
    private static Connection conn = null;
    private static Statement st;
    private static ResultSet rs;    

    /** Creates a new instance of UsuarioDAO */
    public UsuarioDAO() {
    }
    
    private static void Conecta(){
        try {
            conn = ConnectionFactory.getConnection();        
        } catch (SQLException ex) {
            ex.printStackTrace();
        }        
    }
   
    public static List <Usuario> BuscarListaUsuario() {
        Usuario userTemp; 
        List <Usuario> listaUserTemp = new ArrayList <Usuario> ();
                
        try {            
            Conecta();
            st = conn.createStatement();
            rs = st.executeQuery("Select * from Usuario");
            while (rs.next()) {     
                userTemp = new Usuario();
                userTemp.setUsusId(rs.getInt("us_usID"));
                userTemp.setUsusNome(rs.getString("us_usNome"));
                userTemp.setUsusLogin(rs.getString("us_usLogin"));
                userTemp.setUsusPassoword(rs.getString("us_usPassoword"));
                userTemp.setUspePerfil(rs.getString
                ("us_pePerfil"));                                    
                listaUserTemp.add(userTemp);
            }
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
        return listaUserTemp;
    }            
}

Para tentar diminuir cortei algumas coisas, por os métodos criados pelo NB 5.5, como o initComponents(), imports e declaração de JTextFiels e JLabels, mas no meu código esta completo e aparentemente funcioando.

Bom se alguém tiver boa vontade e paciencia para analisar meus códigos e me orientar, vou ficar realmente muito grato. De coração.

Um abraço a todos.

Amigo,
Infelizmente acho que não posso lhe responder com propriedade se está correto ou não.
Também sou novato, e estou há algum tempo pesquisando sobre MVC e DAO.
Acabei chegando na mesma conclusão que você, e estou implementando (quase) da mesma maneira. Especificamente:
Camada Model
Aqui eu fiz minhas classes que são entidades com seus atributos, setters e getters.
Camada Controller
Aqui eu fiz minhas classes DAOs que vão realizar a persistencia (via JDBC), são os métodos de inserir, alterar e excluir. Além de um método que retorna um objeto de uma classe através do atributo identificador e outro que retorna um List de objetos desta classe.
Camada View
Aqui eu fiz meus formulários (com swing) que busca um List da respectiva classe no DAO e monta o JTable, JTextFields e afins.

A unica coisa é que os métodos da classe que você chama de UsuarioModel eu colocaria na camada de visão.

Só também não sei se estou certo.

Abraços

Boa noite amigo…

Como disse tambem sou novato, no entanto gostaria de questioná-lo em alguns pontos, quem sabe assim conseguimos um ajudar o outro, não ?

Sobre a camada Model:
Concordo em classe classificar a classe que definem um objeto Usuario, por exemplo no meu caso, com pertencente a essa classe, ou seja, no meu caso tenho a classe Usuario.java que define um objeto usuário, com todos seus getters e setters.
No entanto achei que nessa camada tb colocaria a classe DAO que faz acesso e persistencia no BD.

Na camada Controller no meu exemplo, eu entendi que ficaria a minha classe UserModel, que no meu caso será responsável pelas regras de negócio.

E no que parece que concordamos plenamente, que seria a camada View, estaria a minha classe CadastroUsuario, que cria a tela para interface com usuário.

Este problema de MVC realmente está começando a chegar no limite.

Primeira coisa que todos devem se lembrar é : Esqueça que existe MVC.
Segunda coisa a lembrar : MVC não é uma forma de diferenciar o sistema em camadas em em pacotes. Aliás MVC percente apenas a 1 camada e 1 pacote.

Dito isto, esqueçam , por amor de Deus que MVC existe.
O que estão querendo e separação de responsabildade.
Vcs querem uma parte do código que construa e mostre a tela.
Uma parte que responda aos eventos da tela.
Uma parte que acesse ao banco de dados e/ou faça pesquisas de dados.

A parte que constroi e controla a tela é a parte swing. Criam JFrames com controles lá dentro , num certo layout etc…
Quando estiver funcionando a tela gerará eventos. Esses eventos vão para objetos listeners. Para começar, crie uma inner classe do frame que ouve todos os eventos necessários e responde conforme. Depois, quando entender o que está acontecendo vá separando as classes cadas vez mais, até que a controladora nem saiba que existe uma tela. Isso é um estágio MUITO avançado que não é recomendo em estágio inicial.

Qual é a arquitetura melhor para uma aplicação desktop com swing ?

  1. Criação de Tela: Espera-se que o programador não tenha que criar todos os botões e layouts na mão. Alcançar um mecanismo bom para isto é complicado, mas existem frameworks por ai. O que deve ser dado a esta parte são os controladores de apresentação. Ou seja, as classes que recebem e respondem a eventos e decidem o que ha a fazer.
  2. Controlo de tela. Espera-se que exista um conjunto de tipos de objeto que respondem aos eventos da tela e controlam o programa. É aqui que ficam os códigos que fazem alguma coisa. Claro que, cada tipo de evento, tem o seu tipo de controle. Ao apertar um botão uma ação é iniciada. É preciso saber qual a ação e recolher parâmetros. Isto é diferente de responder a uma seleção de uma linha numa tabela ? Quando menos for, melhor será a sua abstração e melhor será o objeto de controle.
    O inverso também é verdade. Se eu quiser mostrar m texto na tela, tenho que saber qual o label onde escrever o texto, ou não ? Quando menos eu tiver que saber da tela e seus objetos, melhor.

Atingir estes niveis de abstração e facilidade de controle não é simples. Por isso, para começar comecem por entender os objetos básicos. O que é um JComponent e quais tipos tem disponíveis. Sabes quais eventos eles geram é importantissimo. O resto é experiencia. É repetir , melhorar , aprender com os erros. Ler muito, e ENTENDER o que se lê.
Depois , daqui a um tempo, verá que tem muita coisa repetitiva e tentará colocar isso em classes à parte. Ou usar um framework swing (ou awt ou outro qq). Mas isso é no futuro. Por agora faça a coisa mais simples.

E por amor de Deus não digam que isto é MVC.

Grato pela ajuda…

Sua definição exclareceu quase todas as dúvidas…

Essas posturas são realmente motivadoras.

Zeed01, o fórum é lugar público e não tem como evitar a presença de ninguém. O negócio é invocar setModeIgnore(“On”) para individuos que só fazem barulho e continuar tentando resolver seu problema na boa.

Alguns links que podem te ajudar com o seu problema:

Esse é fundamental. Nele você vai ver que Swing implementa um MVC modificado, chamado pela Sun de separable model architecture, porque junta View e Controller, mas os separa do Model.

Se você pensar em algo bem próximo do MVC para o seu aplicativo, então isto aqui vai te ajudar bastante.

Aqui no GUJ, também já discutimos sobre isso.

Mas não pare ainda não! Tem uma série de outros artigos interessantes, padrões sugeridos, pelos arquitetos do Swing, no site do JGoodies, etc. Ou seja, se quiser trabalhar com o Swing vai ter que ler bastante, entender, suar a camisa.

O que falta às vezes é um exemplo. Pelo menos até agora eu não achei nenhum.

Uma aplicação com o rótulo: “ISSO FOI DESENVOLVIDO COM MVC”

Proporcionaria uma melhor compreensão

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

Ae galerinha, aqui vai um material + do que basico so bre mvc:

http://www-usr.inf.ufsm.br/~marvin/monografia.pdf

[quote=Guto_Magalhaes]Ae galerinha, aqui vai um material + do que basico so bre mvc:

http://www-usr.inf.ufsm.br/~marvin/monografia.pdf[/quote]

Nossa, essa monografia tem uns problemas conceituais bem graves.

Lendo a monografia eu fiquei com algumas dúvidas:
A camada Model “conversa” com as outras ou só o inverso é permitido?

Quem faz a persistência afinal é a Model, ou a Controller?
A Model não é para ser o Bean da entidade?
A Controller não é por exemplo um DAO?

Até onde vi a camada model ou qualquer uma das outras não significa uma única classe e sim uma divisão de responsabilidades, para atender a essas responsabilidades podemos ter uma classe ou um conjunto de classes.

Sendo assim, o bean da entidade e a classe DAO poderiam juntas compor a camada model.

A camada controller ficaria com a validação das regras de negócio, mas ainda estou com dúvida sobre como delimitar isso…

Por exemplo: supondo que uma dessa regras seja que o nome do cliente não pode ficar em branco… onde essa validação ficaria: no método set da classe cliente que é responsavel por não permitir que um objeto Cliente seja criado com atributos inválidos ou num método de validação da classe contoler ?

Como devem ter percebido também sou novato… sendo assim peço que nos ajudem a aclarar esses conceitos…

Obrigado.

Abraços a todos.

Encontrei um artigo muito bom e de fácil entendimento:

http://www.portaljava.com/home/modules.php?name=Content&pa=showpage&pid=138

Acho que minhas dúvidas foram totalmente sanadas agora.

Bom vou dar minha humilde opiniao…

Acredito que vocês estejam se confundindo com dois padroes de arquitetura:

  1. MVC

  2. Três Camadas (Que vi em alguns lugares o pessoal chamando de MVC, ou um MVC midificado.)

  3. MVC
    O MVC trabalha da seguinte maneira:
    O VIEW enviar uma uma ação pro Controller. O CONTROLLER atualizar o MODEL, e o VIEW é atualizado diretamente pelo MODEL. Logo ele apresenta uma estrutura TRIANGULAR. Utilizam o pattern OBSERVER.
    Ver figura: http://upload.wikimedia.org/wikipedia/commons/2/2e/ModelViewControllerDiagram.svg

  4. Três Camadas
    A confusão se segue por que muitas pessoas chamam essa arquitetura também de MVC.(inclusive vi no site da sun eles falando que é um MVC modificado). Apesar de possuir os conceitos similares de MODEL, VIEW e CONTROLLER elas são organizadas em camadas.
    MODEL = Camada de Persistencia
    VIEW = Camada de Apresentação
    CONTROLLER = logicao de negócios

A PRINCIPAL DIFERENÇA é:
No modelo 3-Camdas ou (Multi Camadas) o VIEW fala apenas com o CONTROLLER. E este se comunida com o MODEL.

Essa arquitetura em 3-Camadas ficou famosa pela utilização desta principlamente em aplicações WEB.

Acredito que o que vocês queiram utilizar é a arquitetura 3-CAMADAS (ou MVC modificado… Chamem como quiser…)

Espero que possa ter ajudado!