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