Introduction au pattern MVP en C#
Il existe une alternative très intéressante à la programmation en MVC, c'est le pattern MVP. Concrètement cela consiste à séparer le backend des écrans via des variables intermédiaires interceptées via des get/set dans l'interface utilisateur. Bien sur on s'appuie sur une séparation entre les interfaces (les contrats) et les implémentations.
Je vous propose donc de créer une application webform en utilisant cette pattern avec comme simple exercice, la création d'un additionneur.
On distingue 3 étapes clés :
- La création du modèle, l'interface et son implémentation
- La création du présentateur (presenter en anglais), son interface et son implémentation
- L'implémentation du présentateur dans l'interface utilisateur.
Etape n°1 : créons notre page web en webform
Ajoutez deux textbox
txtValeur1 et txtValeur2
Ajoutez un bouton
button1
Ajoutez un label
lblResult
Vous devez avoir ce genre de code
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="myFirstPresenter._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txtValeur1" runat="server"></asp:TextBox>
<asp:TextBox ID="txtValeur2" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
<asp:Label ID="lblResult" runat="server" BorderStyle="None" Text="Label"></asp:Label>
</div>
</form>
</body>
</html>
Etape n°2 : Créons notre modèle
Le modèle contient en fait les classes métiers servant par exemple à accèder au backend. Dans ce cas nous devons utiliser un couple interface implémentation (cela me rappelle le couple .h .c en programmation C au risque de faire vieux).
Nous créons d'abord une interface dans le fichier IMyMath.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace myFirstPresenter
{
public interface IMyMath
{
double DoAdd(double valeur1, double valeur2);
}
}
Puis nous créons son implémentation dans le fichier MyMath.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace myFirstPresenter
{
public class MyMath : IMyMath
{
public MyMath()
{
//Constructeur
}
public double DoAdd(double valeur1, double valeur2)
{
return valeur1 + valeur2;
}
}
}
Constatez que dans l'interface nous n'avons que la méthode qu'on va invoquer mais que dans l'implémentation on a un constructeur. D'ailleurs il aurait été possible d'utiliser un singleton dans l'implémentation.... C'est ce qu'on fait pour des accès à des backend comme SAP par exemple.
Etape n°3 : Créons notre présentateur et son interface.
L'interface va contenir uniquement les variables et objets qui seront échangés entre le backend et l'interface utilisateur. La class de présentation elle implémentera les actions sur ces données intermédiaires.
Nous créons d'abord une interface IMyPresenter.cs contenant le code suivant
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace myFirstPresenter
{
public interface IMyPresenter
{
string strValeur1 { get; set; }
string strValeur2 { get; set; }
string strResult { get; set; }
}
}
Puis on créée le fichier MyPresenter.cs contenant le code suivant
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace myFirstPresenter
{
public class CPresenter
{
IMyPresenter mview;
public CPresenter(IMyPresenter view)
{
mview = view;
}
public double CalculateAdd()
{
MyMath model = new MyMath();
mview.strResult = model.DoAdd(Convert.ToDouble(mview.strValeur1), Convert.ToDouble(mview.strValeur2)).ToString();
return Convert.ToDouble(mview.strResult.ToString());
}
}
}
Etape n°4 : Intégration de notre présentateur dans notre interface utilisateur
Allez sur le fichier du code de votre page web par défaut default.aspx.cs...
Puis éditer le contenu de la manière qui suit
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myFirstPresenter
{
public partial class _Default : System.Web.UI.Page, IMyPresenter
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
CPresenter presenter = new CPresenter(this);
presenter.CalculateAdd();
}
public string strValeur1
{
get { return txtValeur1.Text; }
set { txtValeur1.Text = value; }
}
public string strValeur2
{
get { return txtValeur2.Text; }
set { txtValeur2.Text = value; }
}
public string strResult
{
get { return lblResult.Text; }
set { lblResult.Text = value; }
}
}
}
Remarquez que dans la classe on hérite à la fois de System.Web.UI.Page MAIS aussi de notre interface du présentateur IMyPresenter. Il suffit alors d'implémenter des get/set ou on fera le lien entre les contrôles comme les textbox, les labels, les datagrid, et les données contenues dans notre interface de présentation. C'est la clès de ce pattern.... Jouez avec pour comprendre.
Vous n'avez plus qu'à compiler et jouer avec ce code....
Conclusion
Ce pattern permet via les interfaces de changer ses implémentations pour les tests. Cela facilite les tests... Mais si vous implémentez Castle Windsor ou nHibernate en prime, vous aurez ni plus ni moins le début du modèle de développement idéal pour SharePoint.