Compartilhar via


Utilizando o padrão MVP com ASP.NET (pt-BR)

Não podemos dizer que o padrão MVP (Model-View-Presenter) é recente, mesmo por que foi proposto no início dos anos noventa. Mas ainda assim parece novo para muitos desenvolvedores, que ainda não se familiarizaram com ele.

O padrão MVP é derivado do conhecido padrão MVC, onde os componentes Model, View e Controller se comunicam. Em uma breve descrição do padrão MVC podemos dizer que a View representa a visualização propriamente dita, sendo representada por um Web Form, Windows Form ou outra forma de interface com o usuário. O Model é responsável por tratar os dados e os comportamentos da aplicação, e o Controller contém a lógica necessária para conectar o Model à View, convertendo as ações da View em eventos que o Model é capaz de tratar.

O motivo pela qual descrevi brevemente o padrão MVC, é que ele inspirou e serve de base para o padrão MVP, onde o Presenter assume o lugar do Controller. Mas por qual o objetivo ? 

No padrão MVP a View não se comunica com o Model, chamamos esta abordagem de Passive View. Neste caso, como o nome sugere, a View é completamente passiva e deixa para o Presenter o papel de tratar suas ações e dizer quando e como ela deve ser atualizada.

A organização proposta pela abordagem Passive View é excelente, mas implica em maior complexidade para tarefas simples como preencher controles (Data Binding). E é por este motivo que existe ainda uma segunda abordagem no padrão MVP, o Supervising Controller, onde a única diferença é permitir que a View acesse o Model, mas somente para realizar Data Bindings.

Diagrama das duas abordagens distintas:

http://www.silverlightshow.net/storage/userfiles/PassiveViewAndSupervisingController_3.gif

Explicado o funcionamento do padrão, gostaria de demonstrá-lo na prática (abordagem Passive View), utilizando um simples exemplo em ASP.NET.

Começaremos pela View, um simples WebForm contendo um TextBox para informarmos o valor, um botão para disparar a ação e uma Label para exibir o resultado:

01.  <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SampleView.aspx.cs" Inherits="MVPSample._SampleView" %>
02. 
03.  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "      http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd    ">
04. 
05.  <  html xmlns="http://www.w3.org/1999/xhtml">
06.  <  head runat="server">
07.            <    title    ></    title    >  
08.  </  head  >
09.  <  body  >
10.            <    form id="frm" runat="server">
11.            <    div    >  
12.                Value: <    asp:TextBox runat="server" ID="txtValue" Text="8" /><br /><br />
13.                <    asp:Button runat="server" ID="btnGetNamedValue" Text="Get Named Value"
14.                    onclick    =    "btnGetNamedValue_Click" /><br /><br />
15.                <    asp:Label runat="server" ID="lblNamedValue" />
16.            </    div    >  
17.            </    form    >  
18.  </  body  >
19.  </  html  >

Para que o Presenter seja capaz de manipular a View ele deve possuir uma referência a ela, e para tanto utilizaremos uma interface:

1.namespace MVPSample.Interface
2.{
3.    public interface  ISampleView
4.    {
5.        void ShowNamedValue(string namedValue);
6.    }
7.}

Code-Behind da View, implementando nossa interface:

01.using System;
02.using System.Web.UI;
03.using MVPSample.Interface;
04.using MVPSample.Presenter;
05. 
06.namespace MVPSample
07.{
08.    public partial  class _SampleView : Page, ISampleView
09.    {
10.        private SamplePresenter _presenter;
11. 
12.        protected override  void OnInit(EventArgs e)
13.        {
14.            this._presenter = new  SamplePresenter(this);
15. 
16.            base.OnInit(e);
17.        }
18. 
19.        public void  ShowNamedValue(string namedValue)
20.        {
21.            lblNamedValue.Text = namedValue;
22.        }
23. 
24.        protected void  btnGetNamedValue_Click(object sender, EventArgs e)
25.        {
26.            int value = Convert.ToInt32(txtValue.Text);
27. 
28.            this._presenter.GetNamedValue(value);
29.        }
30.    }
31.}

Note que a View delega a execução das ações (eventos) ao Presenter.

Estando definida a View, vamos ao Model, que em nosso exemplo possui uma lógica simples de receber um valor numérico e devolver um comentário equivalente:

01.namespace MVPSample.Model
02.{
03.    public class  SampleModel
04.    {
05.        public string  GetNamedValue(int  value)
06.        {
07.            if (value <= 5)
08.            {
09.                return "Poor";
10.            }
11.            else if  (value > 5 && value <= 10)
12.            {
13.                return "Avarage";
14.            }
15.            else if  (value > 10)
16.            {
17.                return "Great!";
18.            }
19. 
20.            return "Ivalid value!";
21.        }
22.    }
23.}

E finalmente o tão esperado Presenter, que conhece muito bem a View e** **o Model, e irá conectá-los:

01.using MVPSample.Interface;
02.using MVPSample.Model;
03. 
04.namespace MVPSample.Presenter
05.{
06.    public class  SamplePresenter
07.    {
08.        private ISampleView _view;
09. 
10.        public SamplePresenter(ISampleView view) 
11.        {
12.            this._view = view;
13.        }
14. 
15.        public void  GetNamedValue(int  value)
16.        {
17.            string namedValue = new SampleModel().GetNamedValue(value);
18. 
19.            this._view.ShowNamedValue(namedValue);
20.        }
21.    }
22.}

Conforme descrito o Presenter recebe as ações da View, realiza os tratamentos necessários junto ao Model, e termina atualizando a View.

Para simplificar o exemplo ignorei as validações, mas lembrem-se delas em suas implementações.

Abraços,
Daniel Cheida de Oliveira