Há alguns meses fui incumbido da tarefa de modificar uma aplicação desktop, de modo que ela possa interagir também com dispositivos móveis que conectam-se a ela remotamente. Como não tinha conhecimento sequer de Orientação à objetos, dediquei-me até ao presente momento a entender o básico, e compreender como esse programa que terei que adaptar funciona. Inicialmente parecia tudo certo, o programa parecia estar utilizando o pattern MVC da maneira correta. Porém, após estudos, percebi que ele funciona de uma maneira um pouco diferente.
Teoricamente, nas aplicações MVC, a parte View da aplicação fica observando a parte Model, para poder modificar-se quando algum evento ocorre, certo? Nessa aplicação, não foi implementado assim. Existe a divisão de código normalmente, do que é control, model e view. Porém, a “camada” view não fica observando o que ocorre em model. Basicamente, quando um evento ocorre, control modifica model, e posteriormente ele mesmo (control) altera view. Exemplo: supondo um programa de cadastro de pessoas com as seguintes classes:
class Pessoa (faz parte de model)
class ControlPessoa (faz parte de control)
class ExibePessoa (faz parte de view)
Quando a instância de ControlPessoa for acionada para exibir uma pessoa, ela cria um objeto Pessoa, com dados recuperados do banco, e na própria classe ControlPessoa é criado um objeto ExibePessoa para mostrar esses dados. Se o objeto já existir ele é apenas alterado. Ou seja, ao invés de view notar que houve uma mudança em model, quem notifica essa mudança é o objeto que faz o controle. Isso está errado? Quando eu uso MVC eu sou obrigado a utilizar o pattern Observer? Mesmo com o programa inacabado, é visível que isso funciona bem e não é tão complicado fazer a manutenção. O único inconveniente que eu vi até o presente momento é o fato das classes control ficarem “poluídas” com chamadas a objetos que pertencem ao pacote view. Outro detalhe interessante é que é possível modificar toda a parte view alterando somente os elementos que pertencem a ela.
Enfim, gostaria que opinassem sobre essa maneira de construção. Se é comum, alguém já usou, e quais as vantagens de fazer assim invés de usar o pattern Observer…
Interessante seu post, eu também trabalho bastante com Swing e implemento o pattern MVC do mesmo jeito.
Geralmente tenho um painel ou frame principal que tem uma referencia direta para a classe de controle, e todas as acoes que o usuario faz na tela, vao direcionadas para o controle, que por sua vez delega a acao para uma outra classe que eh o modelo. Quando o modelo eh alterado, eu notifico o controle que volta chamar a classe view ( ou dependendo do caso, abre outra classe view).
Tb utilizo minha classe controle para configurar as classes views e deixa-las visiveis conforme necessario.
Acabo deixando tudo em pacotes separados (dao, bl, ui) e tento deixar minha arquitetura parecida com MVC web (como o Struts), funciona bem para mim e a manutencao eh facil e rapida.
Faz algum tempo, tentei fazer um framework para configurar tudo dinamicamente e de maneira flexivel, mas percebi que na pratica nunca reusa realmente minhas interfaces graficas em mais de um lugar, somente reaproveitava mais a logica de negocio.Tb tentei pesquisar frameworks MVC para Swing e nao achei nenhum promissor, mesmo o JGoodies MVC me pareceu confuso e o projeto estava meio abandonado.
Se alguem souber de alguma solucao open-souce, por favor, indique.
No MVC, O MODEL NÃO DEVE TER CONHECIMENTO SOBRE A VIEW. Ou seja, o model deve estar totalmente desacoplado da view. Uma das formas de se conseguir isso é tornar os objetos do modelo observáveis, para que quaisquer modificações no modelo se propaguem automaticamente pelas suas visões. Resumindo: não é que seja obrigado, mas lendo o livro da Gangue dos Quatro, dá pra pensar que o padrão Observer foi criado justamente para resolver esse problema de desacoplamento V-M.
O controle deve apenas “traduzir” as operações do usuário em modificações no modelo.
Abraços
Se for seguir o MVC a risca, é preciso que faça toda a camada modelo de forma independente (até mesmo um pacote jar) que deve ser executada e testada (pode ser JUnit) independente de qual tipo de View vc vai usar (Swing, jsp, framework), assim, se tiver mudanças no modelo está tudo encapsulado.
Eu achei uma maneira diferente de implementar o pattern Observer (até o presente momento só conhecia aquele método de herdar Observable e implementar Observer). Não sei se é essa que vocês utilizam, mas parece ser até mais vantajoso:
Bom, com a explicação de vocês e esse novo texto vou dar mais uma estudada. Algumas coisas ainda não ficaram claras, como o momento em que eu criarei as instâncias do objeto. Acho que é só pensar pra compreender a nova idéia!
Valeu pela ajuda de todos, qualquer coisa volto a postar!
public interface Observer {
void update();
}[/code]O livro da gangue dos quatro sugere a herança, mas isso não precisa ser levado ao pé-da-letra, pois no livro ela é utilizada apenas para ilustrar que as classes envolvidas nos padrões possuam uma interface comum.
Na verdade estive olhando o código que mencionei no início e ele ainda tem mais alguns detalhes. O funcionamento seria assim:
Existe uma classe no pacote view, que chama-se ActionSupport. Ela, basicamente, é uma classe genérica pra cadastrar eventos em alguma classe Controller. Quando uma classe view precisa de uma classe para controle, ela faz uma instância de ActionSupport. Acho que é apenas pra não tornar o código repetitivo, fica mais bem estruturado dessa maneira do que repetir essas mesmas classes sempre que necessário.
Ainda assim, View não observa Model diretamente. Controller continua tendo uma referência a objetos view e chama os métodos quando necessário. Novas instâncias das classes do pacote view também são geradas nas classes do pacote Controller. Exemplo, existe uma classe chamada MainFrame, e para controlá-la uma chamada MainControl. Quando é necessário exibir uma nova janela, ela é instanciada em MainControl.
Um outro problema que encontrei é que nessa classe ActionSupport os eventos são do tipo java.awt.event. Agora preciso achar algo não dependente de awt. Talvez o texto que eu mesmo mencionei antes venha bem a calhar. Ainda que eu tenha achado ele meio confuso em certos momentos (ou melhor, muito código a mais em alguns locais).
Bom, obrigado mais uma vez pelas respostas. As coisas, aos poucos, ficam mais claras. Valeu!
O MVC “versão web” sofre algumas modificações. Enquanto que em desktop o model propaga as modificações via Observer, em um sistema web creio que seja mais fácil deixar essa tarefa para o controle mesmo.
Vale a pena investigar o padrão MVP (Model View Presenter), que é uma variante do MVC, bastante interessante de ser aplicado usando TDD. A idéia do MVP é manter a lógica da camada de apresentação no Presenter, deixando a View como uma “casca fina” apenas encarregada da exibição.
Alexandre, há alguns dias dei uma lida superficialmente a respeito desse padrão. Vou ler os links que você sugeriu. Não sei se nesse caso será o melhor, uma vez que eu já possuo uma base utilizando o MVC. Mesmo assim, valeu, vou ler e se surgir alguma dúvida voltarei a postar aqui!
É normal um padrão arquitetural possuir variações na implementação e apesar da arquitetura do Swing ser baseada numa dessas variações de MVC é possível outras soluções, com uma maior separação entre view e controller.
Uma diferenca importante do MVC em relação ao MVP está no Model. No MVC o model conhece a domain layer enquanto que no MVP o Model é a própria domain layer.
Editado: Wagner, acredito que a solução que você tem em maos é uma versão do MVC baseada no padrao mediator como descrito em Larman1998 e aqui utilizando Observer/Command.
Pensando em MVC ou MVP: quando precisamos fazer validações nos dados na view (javascript: o clássico campo email validado via expressões regulares ou Campo X requerido), existe algum pattern para “injetar” essas validações com pouco ou nenhum vinculo com o Model?
[quote=cmoscoso]É normal um padrão arquitetural possuir variações na implementação e apesar da arquitetura do Swing ser baseada numa dessas variações de MVC é possível outras soluções, com uma maior separação entre view e controller.
Uma diferenca importante do MVC em relação ao MVP está no Model. No MVC o model conhece a domain layer enquanto que no MVP o Model é a própria domain layer.
Editado: Wagner, acredito que a solução que você tem em maos é uma versão do MVC baseada no padrao mediator como descrito em Larman1998 e aqui utilizando Observer/Command.
Editado: Corrigido nome do autor.[/quote]
Perfeito. Parece ser isso mesmo. A única coisa que não ocorre (pelo menos não explicitamente) é uma classe model notificar uma classe controller. Quero dizer, não tem nada cadastrado como observador ou algo assim. Mas funciona desse modo mesmo, algumas classes controller alterando view diretamente. Uma vez que isso está funcionando bem, e pelo que vi não é errado, vou manter do mesmo jeito.
O desafio pra mim vai ser utilizar outros tipos de eventos. Até o presente momento o código utiliza os eventos pertencentes a java.awt.event. Eu acho que se utilizar o padrão que mencionei naquele link, vai ficar algo mais genérico. Pensando nesse caso, pra mim alterar view eu teria que alterar controller, por causa dos eventos, isso é normal? Acho que uma hora ou outra é preciso mexer nos dois pacotes, já que pra mim enviar as requisições para um dispositivo móvel, ou mesmo pra fornecer dados em uma página web eu não utilizaria AWT.
Fiz uma pesquisa no fórum sobre MVC, e os tópicos me levaram a vários links interessantes. Porém, quanto mais eu leio sobre MVC, mais confuso eu fico. :?
Pensem em uma aplicação Swing desktop acessando um banco de dados. Eu tenho as classes que representam o modelo do domínio do sistema, que certamente farão parte do Model, e tenho as classes que implementam os formulários da View. O controle nesse caso é o quê? São as classes que tratam os eventos? Ou o MVC nesse caso se restringe apenas ao Swing, que implementa o modelo através de classes como Document ( cujo controle é o JTextField ) ou AbstractTableModel ( cujo controle é o JTable )?