Home > Artigos > Engenharia de Software >
Apresentando Model-View-Presenter, o MVC focado na visualização
Publicado por Tutoriais Admin em 17/08/2009 - 55.094 visualizações
Daniel Fernandes Martins
dfmwork @ gmail.com
Neste artigo serão abordados os aspectos principais do padrão MVP, ou Model-View-Presenter. Serão explicados quais problemas motivaram a criação desse padrão, como ele resolve tais problemas e, principalmente, os as vantagens e desvantagens de se usar o MVP. Para demonstrar esses conceitos de forma prática, nós desenvolveremos uma aplicação de exemplo utilizando Swing.
O modelo de programação MVP é o que podemos chamar de uma derivação do modelo MVC, que surgiu com o Smalltalk. No Smalltalk, os componentes visuais, como as caixas de texto e botões, são regidos por três abstrações centrais: Model, View e Controller.
- Model: São informações que indicam o estado do componente, como, por exemplo, o texto de um TextField ou a indicação on-off de um CheckBox;
- View: Acessa os dados do Model e especifica como os dados do Model são mostrados ao usuário, como, por exemplo, um texto dentro de um TextBox ou um & # 61692; indicando que um CheckBox está marcado;
- Controller: Componente para mapear as ações do usuário na View (as quais ocorrem normalmente através de eventos) e fazem com que o Model seja modificado. Para citar um exemplo, quando um CheckBox? marcado? recebe um evento de click, o Controller mapeia essa ação do usuário e modifica o Model, indicando que este agora está desmarcado. O Model, por sua vez, notifica a View, indicando mudança em seu estado. A View recebe a notificação e renderiza o CheckBox desmarcado na tela.
A Figura 1 ilustra a interação entre o Model, a View e o Controller:
Figura 1? Modelo MVC
Este modelo de programação funciona muito bem no contexto de componentes individuais, como explicado anteriormente. Porém, durante o desenvolvimento, é necessário agrupar vários desses componentes sob contextos específicos que, juntos, representam o domínio do problema a ser solucionado pelo sistema.
Imagine uma janela que sirva para cadastrar clientes no sistema. É agrupado um conjunto de diversos tipos de controles visuais (View) que representam uma lista de objetos Cliente no sistema (Model). O resultado da interação do usuário com a janela é traduzido em eventos (Controller), que controlam o fluxo da aplicação e modificam o estado dos controles da janela, atualizando também os objetos de negócio.
Na maioria dos casos, o código responsável pelo tratamento dos eventos e controle de fluxo da Janela fica dentro de uma mesma classe. Temos então uma quebra de camadas: a View não deve conhecer nem o modelo que representa e nem a lógica de apresentação, já que temos alguns tipos de ação na lógica de apresentação que são regidas pelo domínio do problema em questão. Outro problema de manter tanto o código de montagem da tela quanto o tratamento de eventos é uma classe extremamente grande, difícil de manter, difícil de expandir e com código de impossível reutilização.
É aí que entra o MVP!
Motivações do MVP
A diferença entre o MVC e o MVP fica basicamente no conceito, já que as funções do? C? (Controller) do MVC são semelhantes ao? P? (Presenter) do MVP.
Imagine novamente o exemplo do cadastro de clientes. O Model é a coleção de objetos Cliente que são manipulados pela janela. A View é a janela propriamente dita. O Presenter é responsável por interceptar os eventos gerados na View, com a finalidade de controlar a lógica de apresentação.
Portanto, foco principal do MVP é separar a lógica de apresentação da apresentação em si. Com isso, conseguimos alternar entre diferentes apresentações facilmente, através da reutilização da lógica de apresentação. Além disso, conseguimos realizar testes na classe responsável pela lógica de apresentação sem precisar utilizar a View para isso. Ganhamos também no quesito manutenção, já que as responsabilidades foram divididas em mais classes especializadas e fáceis de entender.
MVP na Prática
Já que o? coração? do MVP é a separação da lógica de apresentação da apresentação em si, temos como resultado uma View que não contém muito código além necessário para organizar os componentes na tela. Isso parece ser o caminho mais correto, pois a função da View deve ser somente oferecer uma forma de o usuário interagir com o sistema. Note aqui uma semelhança com o padrão MVC clássico.
Considere o seguinte diagrama de classes:
Figura 2? Estrutura de classes do exemplo, seguindo o MVP.
Para criar a nossa aplicação de exemplo, utilizaremos como base o diagrama de classes mostrado na Figura 2.
Todas as Views capazes de cadastrar clientes devem implementar a interface CadastroClienteView. Essa interface define métodos get () e set () para configurar os valores dos componentes, habilitar / desabilitar entrada de dados nos componentes visuais e quaisquer outras operações que sejam necessárias. Essas operações são utilizadas pelo Presenter, que no caso é a classe CadastroClientePresenter. Como mostrado na Figura 2, a classe CadastroClientePresenter se registra como observador dos eventos disparados na View, e os trata.
Para ilustrar melhor a interação entre as classes definidas na Figura 2, considere o seguinte diagrama de seqüência:
Figura 3? Procedimento de inserção de um novo cliente no sistema
Note que o diagrama está dividido em três partes. A primeira parte mostra como ocorre a instanciação da janela de cadastro de clientes: um objeto presenterInstance obtém o objeto windowInstance através de criação explícita (com o operador new) ou injetado via IoC. Em seguida, o objeto presenterInstance inicializa o Model, que no caso é composto por uma coleção de objetos Cliente. Finalmente, o objeto presenterInstance exibe a janela. (Parte 1)
A janela fica aguardando o usuário inserir um novo cliente. Quando o usuário clica no botão? Inserir?, o objeto presenterInstance executa o código responsável por liberar os campos para que o usuário digite os dados do novo cliente, através de chamadas aos métodos definidos na interface CadastroClienteView, que é implementada pelo objeto windowInstance. (Parte 2)
Para confirmar o cadastro, o usuário pressiona o botão? Confirmar?. Em seguida, o objeto presenterInstance cria uma nova instância da classe Cliente e preenche seus atributos, de acordo com os valores digitados na janela. Depois, o Presenter adiciona esse cliente na lista de clientes cadastrados e atualiza a View. (Parte 3)
Para aplicar os conceitos vistos até aqui, vamos criar uma aplicação de exemplo utilizando o pattern MVP.
Aplicativo de Demonstração
As imagens abaixo demonstram o nosso aplicativo em funcionamento:
Figura 4? Janela de cadastro de clientes
Figura 5? Inserindo um novo cliente
Figura 6? Novo cliente cadastrado no sistema
Figura 7? Removendo um cliente cadastrado
A aplicação de exemplo é bastante simples, mas mostra como aplicar o pattern e como utilizá-lo para tornar o desenvolvimento de aplicações rich-client menos traumático.
Ferramentas utilizadas
Para criação desse exemplo, aconselho a utilização da IDE NetBeans, devido a grande facilidade de criação de interfaces gráficas com Swing. Neste programa também usaremos o framework Spring para? colar? os componentes da aplicação sem que seja necessário escrever código para isso.
Criando o Model
Inicie um novo projeto no NetBeans com qualquer nome. Em seguida, crie uma classe chamada Cliente, no pacote org.javafree.mvp.model. Essa classe será o nosso Model.
Cliente.java
Criando a View
Crie um novo JFrame chamado CadastroClienteWindow, no pacote org.javafree.mvp.gui.cadastro .
Crie um layout parecido com a figura abaixo:
Figura 8 ? Layout da aplicação
Esta interface é composta por sete JLabel, seis JTextField, seis JButton, um JScrollPane e um JTable:
| Classe | Objetos |
| JLabel | lbClienteId, lbClienteNome, lbClienteTelResidencial, lbClienteTelComercial, lbClienteTelCelular, lbClienteEmail, lbClientesCadastrados |
| JTextField | txtClienteId, txtClienteNome, txtClienteTelResidencial, txtClienteTelComercial, txtClienteTelCelular, txtClienteEmail |
| JButton | btnInserir, btnRemover, btnAlterar, btnConfirmar, btnCancelar, btnSair |
| JScrollPane | spClientesCadastrados |
| JTable | tableClientesCadastrados |
Para permitir que o Presenter interaja com a View sem saber o seu tipo, precisamos criar uma interface, que deve ser implementada pela nossa View. Assim, nós não estaremos prendendo o Presenter a uma única View.
Ainda no pacote org.javafree.mvp.gui.cadastro, crie uma classe chamada CadastroClienteView.
CadastroClienteView.java
Modifique a classe CadastroClienteWindow, fazendo que ela implemente a interface CadastroClienteView. Adicione o seguinte código na classe CadastroClienteWindow:
Ainda no pacote org.javafree.mvp.gui.cadastro, crie uma nova classe chamada ClientesTableModel. Esta classe será necessária para renderizar o JTable com a lista de todos os clientes cadastrados no sistema.
ClientesTableModel.java
Criando o Presenter
Agora definiremos a classe Presenter, que será responsável pela lógica de apresentação do nosso aplicativo. Crie uma classe chamada CadastroClientePresenter, no pacote org.javafree.mvp.presenter.cadastro .
CadastroClientePresenter.java
Para definir os eventos disparados pela View, criaremos duas classes no pacote org.javafree.mvp.presenter.cadastro: ClientesWindowActionListeners e ClientesWindowMouseListener.
A classe ClientesWindowActionListener contém todas as classes necessárias para tratar os eventos de ação na View, enquanto a classe ClientesWindowMouseListener trata os eventos de mouse. Segue abaixo o código das duas classes:
ClientesWindowActionListeners.java
ClientesWindowMouseListener.java
A criação da camada de lógica de apresentação está quase concluída. Agora que temos as classes que tratam os eventos da View, vamos voltar à classe CadastroClientePresenter e implementar o método setUpViewListeners () como mostrado abaixo:
Para concluir o Presenter, nós precisamos definir o fluxo de operações do nosso aplicativo. Veja a imagem
Figura 9 ? Fluxo dos comandos de Incluir e Alterar clientes
Como mostrado na imagem, a operação de confirmação (que é feita em um único local), deve saber se o usuário está inserindo um cliente no sistema ou se está modificando um cliente já cadastrado.
Para evitar testes do tipo
vamos implementar esta funcionalidade utilizando o padrão Strategy. Assim, quando o usuário pressionar o botão Inserir, a ? estratégia ? executada pelo botão Confirmar é inserir o cliente no sistema. Da mesma forma, se o usuário decidir alterar um cliente, a estratégia do botão Confirmar será alterar os dados do cliente.
Para conseguir esse efeito, vamos criar uma interface chamada Strategy, dentro do pacote org.javafree.mvp.presenter.cadastro.
Strategy.java
Volte à classe CadastroClientePresenter e insira, no final do código da classe, o seguinte código:
Agora, vamos criar dois objetos que representam essas operações. Estes dois objetos devem estar visíveis para as classes tratadoras de eventos, permitindo a definição do fluxo da aplicação.
Estamos quase terminando o nosso Presenter. Abra novamente a classe ClientesWindowActionListeners e modifique o código, como mostrado no trecho abaixo:
Juntando as partes
A nossa aplicação está praticamente finalizada. Só resta agora criar o arquivo de configuração do Spring. Crie um arquivo chamado applicationContext.xml no CLASSPATH da aplicação. Configure seu conteúdo para a listagem exibida abaixo:
Para finalizar a criação do nosso aplicativo, crie a classe Main, no pacote org.javafree.mvp.application.
Main.javaA aplicação está finalizada. Só não se esqueça de adicionar os arquivos spring.jar e commons-logging.jar nas Libraries do projeto.
Conclusão
Se formos comparar duas aplicações, uma delas seguindo o padrão MVP e outra não, é inevitável a comparação entre o código escrito: a aplicação que utiliza o MVP tem mais linhas de código e mais classes do que aplicação que não utiliza o MVP. Eu particularmente não considero isso uma desvantagem, pois justamente a quebra do código em várias classes torna a aplicação mais fácil de entender e de expandir, além de permitir maior re-utilização e melhorar a testabilidade do código.
Referências
Martin Fowler - http://www.martinfowler.com/eaaDev/ModelViewPresenter.html
IBM ? s Taligent - ftp://www6.software.ibm.com/software/developer/library/mvp.pdf
MVC - http://en.wikipedia.org/wiki/Model-view-controller
MVC Meets Swing - http://www.javaworld.com/javaworld/jw-04-1998/jw-04-howto.html
Links
NetBeans - http://www.netbeans.org
Spring Framework - http://www.springframework.org
- Model-View-Presenter (MVP)
- Eliminando codificação Java das páginas JSP
- Arquitetura e MVC
- MVC e MVC2
- Apresentando Model-View-Presenter ....
- JSF + EJB + Hibernate. Como usar os beans da melhor maneira?
- Artigos e Tutoriais do JavaFree.
- Arquitetura de Projeto EE
- Como adequar meu sistema no modelo MVC
- Framework MVC para aplicação desktop

