Olá pessoal.

Recentemente participei de um projeto com grandes desafios. Na ocasião tive a oportunidade de trabalhar com um Design Pattern – O MVP.

Neste post vou apresentar, de uma forma geral, os conceitos básicos relacionados ao padrão.
Iremos focar nos conceitos e alguns detalhes de implementação afim de expandir nossa caixa de ferramentas para nossas aplicações.

MVP

O MVP ou Model View Presenter é um padrão de UI (User Interface)  baseado no MVC (Model View Controler) que nos auxilia no desenvolvimento de aplicações separando as responsabilidades de negócio da UI. Temos muitos ganhos na implementação de soluções com o padrão MVP. O maior ganho, em minha opinião, é o desenvolvimento com testes de unidade.

O diagrama abaixo apresenta o conceito do padrão:

Padrão MVP

Padrão MVP – Fonte: MSDN(https://msdn.microsoft.com/en-us/library/ff649571.aspx)

 

O Presenter tem a dependência de uma Interface de View. Esta interface ou contrato é a ligação entre a UI(Web, Mobile, Console, etc) e o back-end da aplicação. Temos uma semelhança do Presenter com o Controler do padrão MVC.

Praticando

Para melhor entendimento dos conceitos abordados sobre o padrão, nada melhor do que praticar!

O projeto que serviu de inspiração para este artigo utilizou os conceitos do padrão para um sistema Web com a tecnologia ASP.NET Web Forms. Em nosso exemplo, além de utilizar o ASP.NET Web Forms, também criaremos um projeto Console Application e demonstrar o poder do padrão em Views(UI) diferentes.

Abaixo um diagrama que representará nossa solução:

Modelo da Solução do Exemplo MVP

Modelo da Solução do Exemplo MVP

  • ExemploMVP.Model – Projeto do tipo Class Library. Será uma abstração de nossa camada de Model. Temos apenas uma classe, Pessoa, para representar uma entidade.
  • ExemploMVP.Presenter – Projeto dotipo Class Library. Contém a abstração da camada de Presenter. Possui os artefatos de classe de Presenter, ViewModel e Interface de View.
  • ExemploMVP.Web – Projeto Web do tipo Web Forms.
  • ExemploMVP.ConsoleApplication – Projeto do tipo Console.

O diagrama de classe acima nos remete os principais artefatos e projetos para evolução dos conceitos abordados, além das associações entre os projetos, classes e interfaces.

Faremos uma simulação de um cadastro de “Pessoa” em nosso sitema. Para isso, serão implementadas funcionalidades básicas o como criar, atualizar, excluir e listar pessoas.

Model

O modelo, basicamente, representa as informações do domínio da nossa aplicação. No caso, estamos representando um cadastro de Pessoas. Mas poderia ser uma locadora de dvds, um sistema de orçamento de obras, etc. Todos os dados que a aplicação disponibiliza estão abstraídos nesta camada.

Vejamos o código abaixo:

Classe Pessoa - Model

Classe Pessoa – Model

Observem que a classe Pessoa contém somente atributos mas nenhum método de negócio. Nosso objetivo é demonstrar a implementação do padrão MVP em uma solução simples e didática para facilitar o entendimento dos leitores.

Em nosso projeto, uma pessoa possui um nome, um código e uma data de aniversário. O construtor da classe faz ageração de um código aleatório para a identificação de um objeto pessoa. Se houver a necessidade, o código poderá ser atribuído através da propriedade Código.

A partir das linhas 29 a 32, estamos sobrescrevendo o método ToString para que seja retornado os dados da pessoa em um formato mais amigável.

View

Quando falamos de View não estamos associando a tela ou formulário. A View, em questão, é uma interface ou contrato. No exemplo, o cadastro de pessoa, será um formulário único para cadastrar e listar os usuários. Abaixo o protótipo da tela de gerenciamento de pessoas:

Cadastro de Pessoa - Protótipo

Cadastro de Pessoa – Protótipo

Como podem ver, nossa tela ou UI contém controles para entrada de dados e exibição dos mesmos, além de botões de comando. Devemos traduzir esta tela em um contrato conforme o código descrito:

IGerenciarPessoaView - View

IGerenciarPessoaView – View

A interface possui apenas propriedades com tipos primitivos e um objeto customizado – PessoaViewModel. Mas qual a relação entre a interface e a tela demonstrada em nosso protótipo?

Nosso protótipo possui 2 campos texto e uma tabela ou grid. Essas são informações que serão obtidas do modelo e também enviadas para o mesmo. Ao criar um Webforms em nosso projeto Web, teriamos, basicamente, 2 TextBox, 1 GridView e 2 Buttons. Além disso devemos resolver a relação da interface de View em nosa UI de forma a cumprir um contrato que será utilizado na classe de Presenter.

A relação entre a UI e o Contrato é simples:

  • O TextBox associado ao nome contém a informação necessário para resolver a propriedade Nome em nossa interface de View – para enviar dados ou receber;
  • O TextBox associado à data de nascimento contém a informação necessária para resolver a propriedade DataNascimento em nossa interface de View – para enviar dados ou receber;
  • O GridView necessida de uma listagem de pessoas para exibição na tela, que deverá ser obtida do modelo.

Conforme descrito acima, temos os requisitos necessários para cumprimento do contrato. A implementação da interface no arquivo GerenciarPessoas.aspx.cs é exibida no código abaixo:

Gerenciar Pessoas Page - UI

Gerenciar Pessoas Page – UI – Resolvendo o contrato da View

No get da propriedade Nome estamos retornando, exatamente, o valor da propriedade Text do TextBox que é a informação contida no controle, informada pelo usuário. Já no set estamos atribuindo ao TextBox um valor.

A propriedade DataNascimento segue o mesmo padrão da propriedade Nome, porém existe um tratamento para converter o valor “string” para um valor “DateTime“.

Esta implementação resolve o contrato da View que será utilizada no presenter sem a necessidade de qualquer tecnologia associada, como TextBox, GridView, etc. Apenas utilizando o polimorfismo, conceito de orientação a objetos, será possível fazer a comunicação entre as camadas propostas pelo padrão – View -> Presenter -> Modelo.

[quote]Uma dica:
Se houvesse a necessidade de inclusão de um Checkbox, no formulário, para que o usuário
informe se a pessoa a ser cadastrada possui carro ou não, seria acrescido na interface de View
uma propriedade do tipo bool. Interessante, não?[/quote]

Presenter

Finalmente chegamos a uma das camadas mais importantes do padrão – a Presenter. Esta camada tem como objetivo controlar e mediar as informações da View para o Model e do Model para a View.

Na presenter implementada para este exemplo há a existência de algumas lógicas de negócio. Esta implementação resume-se apenas para demonstração didática do padrão e facilitar o aprendizado. Em aplicações reais a lógica de negócio deve ser delegada a outras camadas para centralizar e separar as responsabilidades. Abaixo um trecho de código da Presenter:

Presenter - Gerenciar Pessoa Presenter

Presenter – Gerenciar Pessoa Presenter

Na linha 20 existe uma validação que garante que uma pessoa deve ser salva somente se seus atributos, Nome e Data de Nascimento, estão preenchidos. Caso contrário uma exceção é lançada.

A linha 23 tem o código necessário para criar uma nova instância da classe pessoa. Os parâmetros nome e data são informados no construtor da classe. Estes pagâmetros são obtidos através da propriedade do nosso contrato.

A View poderia ser uma página Web, que implemente o contrato, ou qualquer outro tipo de UI. Via polimorfismo a instância do objeto em nosso atributo “_view” implementa o contrato, portanto, para acessar os dados não precisamos nos preocupar se vem de um TextBox ou qualquer outro controle.

Esta abordagem é muito interessante e não se restringe ao MVP.  É muito comum sua utilização para diversas situações para qualquer tipo de projeto. Quando “acessamos” a propriedade _view.Nome estamos acessando propriedade Text de um TextBox, conforme a resolução do contrato na classe do nosso formulário.

Na linha 25 temos a adição da nova pessoa em uma lista estática para simular uma base de dados e em seguida, na linha 27 cé feita uma chamada ao método Limpar para que o mesmo “inicialize” os controles novamente, controlando o fluxo da tela.

Finalmente, na linha  29, retornamos uma string cotendo uma a informação do novo objeto adicionado.

Este método é apenas um dos métodos disponíveis na classe de Presenter. Mas por ser totalmente desacoplado de tecnologia, basta que outras implementações de UI efetuem as implementações de contrato e então utilize o mesmo código contendo todo o fluxo de um cadastro de pessoa sem qualquer alteração.

Conclusão

O padrão MVP é um dos vários padrões disponíveis para resolver nossos problemas de desenho e implementação. Para qualquer solução deverão ser analisadas várias situações para decidir quais tecnologias e padrões utilizar, não sendo necessário focar em somente uma linha de raciocínio.

Mesmo assim é interessante aumentar nosso leque de opções, conhecer os pontos fortes e fracos de cada solução e tentar utilizar aquela que vai melhor atender ou o conjunto de soluções que melhor atenderá sua demanda.

Acredito que o padrão, no caso do projeto que inspirou o artigo, trouxe grandes benefícios para o sistema, assim como um melhor planejamento e abstração da solução. Agregou bastante na interação com a tecnologia ASP.NET Web forms. Foi uma forma de se trabalhar e muito interessante.

Solução Final

Todo o restante do código do exemplo encontra-se disponível no GitHub(link em referências). Efetuem o download, testem, verifiquem as demais implementações. Além da solução Web, também existe a implementação de uma aplicação Console Application que utiliza o mesmo Presenter, View e Model. Existem comentários para ajudar no entendimento do padrão. Fiquem a vontade para comentar, postar dúvidas.

Referências