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:



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