Model / View / Controler (MVC)

ImageCalendarCreation   Crée le : 17/12/2010 Calendar   Modifié le : 27/01/2011 ImageOwner   Par : Proteus ImageVisites   Vue : 169 CommentaireCount   Commentaire(s) : 0

Introduction


Lorsque vous avez une application qui possède plusieurs interfaces utilisateur, vous vous heurtez à différents problèmes. Maintenance, Communication, Lisibilité, Séparation du code. Le Design Pattern MVC est là pour aider le développeur à mettre en place des couches de codes qui permettent de trouver des solutions à ces problèmes. Prenons un exemple simple vous avez 3 vues qui vous renvoient certaines informations. Ces informations proviennent de la même table sur la même base de données. Si vous êtes dans un schéma standard et que vous effectuez une modification de votre table, vous n’aurez pas de modification de vos IHM (Interfaces) tant que vous n’aurez pas rechargé votre application.

L’implémentation du modèle MVC permet de déclencher des méthodes définit dans une interface pour des vues qui se sont enregistrées dans une liste de client à informer. MVC est un pattern composé. Il est composé du design Pattern Observer (qui permet de provoquer l’update des vues à la disposition du Modèle) et le Design Pattern Stratégie implémenté dans le modèle en cas de nécessité (il permet d’implémenter une notion d’objet avec un couplage faible afin de ne pas tomber dans les limites de l’Héritage). Il a plusieurs objectifs :

  • Centraliser l’accès aux données
  • Centraliser le contrôle des données qui sont envoyées à votre base de données
  • Automatiser la notion de mise à jour des vues.

Comme vous le verrez tout au long de ce tutorial, l’implémentation de MVC dans vos applications permet de la séparer votre code en plusieurs couches. Vous vous rendrez compte par la suite que la maintenance d’une application sous ce modèle est nettement plus aisé. Je suis conscient qu’il existe, sur la toile, un certain nombre de sites qui traitent du sujet. Mais il était important pour moi d’exposer ici ma vision de MVC.

Modèle


Il contient toute la partie données et toute la logique d’accès à votre base de données. Ici cette séparation d’accès aux données permet de modifier votre base de données sans avoir à modifier la vue de votre application. Dans ce pattern le modèle a également pour but de déclencher la mise à jour des vues qui s’y sont abonnées. Il notifie les vues enregistrées pour qu’elles déclenchent une mise à jour de l’affichage, son rôle :

  • Recevoir des requêtes depuis la vue pour l’affichage des données.
  • Recevoir des données depuis le contrôleur pour mettre à jour le serveur de base de données.
  • Notifier la vue qu’elle doit se mettre à jours.

Contrôleur


Il contient toute la logique métier. Cette classe a pour but de contrôler les données qui sont envoyées à votre modèle afin de s’assurer, par exemple, que les données correspondent bien aux attentes du modèle. Pour le développeur, la classe Contrôleur représente une grosse partie du travail de l’application. Le contrôleur n'effectue aucun traitement, il n'effectue qu'un travail d'analyse pour vérifier la qualité des données qu'il fournit au modèle, son rôle :

  • Envoyer des données au modèle pour qu’il mette à jour le serveur de base de données.
  • Recevoir des actions depuis l’IHM (Ajout, Suppression, Update) pour être contrôlées.
  • Mettre à jour la vue.

Vue / Vues


Elles sont la représentation graphique de votre application. Pour être sûr que vous ne faites pas d’erreur dans le codage de votre pattern, il vous suffit de partir du principe que la vue ne contient que très peu de ligne de code, elle ne doit contenir aucune logique mais simplement une représentation graphique des données que lui fourni votre contrôleur. Dans ce pattern vous devez également garder à l’esprit que votre vue ne demande pas sa propre mise à jour de données mais qu’elle est déclenchée par le Modèle, son rôle :

  • Etre notifié depuis le modèle pour déclencher une mise à jour de l’affichage.
  • Effectuer des actions sur le contrôleur (Ajout, Suppression, Update).
  • Effectuer des requêtes auprès du modèle.

Comment ca marche ?


Comme nous l’avons vu plus haut, la première chose que l’on doit faire c’est de créer pour notre exemple 1 vue (Winform), 1 classe Modèle et 1 classe Contrôleur. Une fois c’est trois classes en place. Nous pouvons entrer dans le vif du sujet. Maintenant vous savez que c’est le modèle qui doit déclencher une mise à jour de la vue. Pour effectuer cet appel notre vue doit implémenter une méthode que nous allons créer dans une interface. En utilisant le système d’héritage, nous allons hériter toutes nos vues de cette interface.

Afin de faire cela proprement nous allons créer une Interface que nous allons appeler « IView » dont le code sera le suivant :

« MVC\Interfaces\IViews.cs »

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MVC.Interfaces
{
    public interface IViews
    {
        void Update();
    }
}

Coté Modèle, dans notre exemple, nous allons juste simuler une fausse base de données déjà chargées.

« MVC\Models\Model.cs »

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using MVC.Interfaces;

namespace MVC.Models
{
    public class Model
    {
        #region Variables
        private static Model instance;
        private ObservableCollection stringCollection = new ObservableCollection();
        private ObservableCollection viewCollection = new ObservableCollection();

        #endregion

        #region Proprietes
        public static Model Instance
        {
            get 
            {
                if (instance == null)
                    instance = new Model();
                return instance; 
            }
        }
        public ObservableCollection StringCollection
        {
            get { return stringCollection; }
            set { stringCollection = value; }
        }

        #endregion

        #region Constructeurs
        public Model()
        {
            stringCollection.Add("Ligne 1");
            stringCollection.Add("Ligne 2");
            stringCollection.Add("Ligne 3");
        }

        #endregion

        #region Methodes
        #region Private
        private void UpdateView()
        {
            foreach (IViews View in viewCollection)
                View.Update();
        }

        #endregion

        #region Public
        public void Add(string Value)
        {
            StringCollection.Add(Value);
            UpdateView();
        }
        public bool Suscribe(IViews view)
        {
            if (!viewCollection.Contains(view))
                return false;
            viewCollection.Add(view);
            return true;
        }
        public bool UnSuscribe(IViews view)
        {
            if (!viewCollection.Contains(view))
                return false;
            viewCollection.Remove(view);
            return true;
        }

        #endregion

        #endregion
    }
}

Alors ici il y a plusieurs choses qu’il convient d’expliquer les Variables, il y en a trois :

  • Une variable d’instanciation pour faire du modèle une classe en mode Singleton.
  • Une variable qui va contenir la liste des vues à mettre à jour.
  • Une variable qui contiendra les données.

Le Constructeur : dans notre classe il est privé, pour qu’on ne puisse l’instancier que par sa propriété Static. Dans le constructeur, nous avons un chargement de données dans notre variable data. Les Méthodes :

  • Update : qui déclenche la mise à jour des vues qui se sont enregistrées dans la liste.
  • Ajouter : qui ajoute des données à la liste de données.
  • Suscribe : qui enregistre une vue dans la liste des vues à updater.
  • UnSuscribe : qui supprime une vue dans la liste des vues à updater.

Coté Contrôleur, il faut mettre en place la stratégie de contrôle qui va contrôler les données avant de demander au modèle d’effectuer une mise à jour des données.

« MVC\Controllers\Control.cs »

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace MVC.Controllers
{
    public class Control
    {
        #region Constructeurs
        public Control() { }

        #endregion

        #region Methodes
        #region Private
        private bool CheckData(string ValueString)
        {
            if (ValueString.Contains("123"))
                return true;
            return false;
        }

        #endregion

        #region Public
        public bool AddData(string ValueString)
        {
            if (!CheckData(ValueString))
                return false;
            Models.Model.Instance.StringCollection.Add(ValueString);
            return true;
        }

        #endregion

        #endregion
    }
}

Ici on effectue simplement un contrôle de la donnée avant de demander au modèle de l’ajouter dans la base. Et enfin la Vue, qui va être l’interface utilisateur et qui va afficher les données et surtout qui va implémenter l’interface IView.

« MVC\Views\MainWindow.xaml.cs »

using System.Windows;
using MVC.Interfaces;

namespace MVC.Views
{
    public partial class MainWindow : Window, IViews
    {
        #region Variables
        private Controllers.Control controller = new Controllers.Control();

        #endregion

        #region Proprietes
        public Controllers.Control Controller
        {
            get { return controller; }
            set { controller = value; }
        }

        #endregion

        #region Constructeurs
        public MainWindow()
        {
            InitializeComponent();
        }

        #endregion

        #region Methodes
        private void CommandButtonAdd_Click(object sender, RoutedEventArgs e)
        {
            bool result = Controller.AddData(TextBoxValue.Text);
            if (!result)
                MessageBox.Show("Rejet de votre valeur", "Check Data", MessageBoxButton.OK, MessageBoxImage.Error);
            TextBoxValue.Text = "";
        }
        public void Update()
        {
            ListBoxData.ItemsSource = Models.Model.Instance.StringCollection;
        }
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Models.Model.Instance.Suscribe(this);
            Update();
        }
        private void Window_Closed(object sender, System.EventArgs e)
        {
            Models.Model.Instance.UnSuscribe(this);
        }

        #endregion
    }
}

Comme pour le modèle il faut ici expliquer les différentes lignes de codes :

  • Héritage : Elle hérite de l’interface IView. Pour que le modèle puisse déclencher la méthode d’Update.
  • Les Variables : Ici elles n’instancient que le modèle et le contrôleur.
  • Les Méthodes : Update(): Qui déclenche une mise à jour de la « ListBox », Window_Loaded : Qui charge la vue dans la liste des vues à mettre à jour depuis le modèle, Window_Closed : Qui retire la vue dans la liste des vues à mettre à jour depuis le modèle, CommandButtonAdd_Click : Qui demande au contrôleur d’ajouter une donnée au modèle.

Conclusion


Le design pattern MVC est un « must » dans les patterns de conception à connaître. En l’implémentant vous résoudrez un grand nombre de problèmes auxquels vous pourriez vous heurter pendant votre phase de développement. J’espère que l’exemple évoqué ici était suffisamment clair, dans le cas contraire n’hésitez pas a me contacter pour plus d’information.

Editer le Message Supprimer le Message ContactMe   Contactez-moi


Laisser un commentaire