begin process at 2008 05 17 16:08:32
1 174 133 membres
250 nouveaux aujourd'hui
13 974 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

DESIGN PATTERN OBSERVER


Information sur le tutorial

Catégorie :Tutoriaux Tutorial .NET ( DotNet ) Date de création : 06/12/2007 20:28:09 Vu : 3 255 fois

Note :
Aucune note

Commentaire sur cette source (3)
Ajouter un commentaire et/ou une note


Description

Design Pattern Observer C#
Présentation du pattern Observer très connu avec un petit exemple simple à l'appui pour illustrer le concept.

Tutorial

Design Pattern Observer

Introduction

Un design pattern est un concept destiné à résoudre des problèmes récurrents suivant un certain paradigme (dans notre cas, celui de la programmation orienté objet). Il existe des dizaines de patterns différents qui simplifient grandement la vie du développeur.

Pour ce premier tutorial sur les designs patterns, j’ai choisi d’expliquer et de proposer une implémentation via un exemple du design pattern Observer. Ce pattern est utilisé pour observer l’état d’un objet dans un programme.

Voici à quoi ressemble ce pattern d’un point de vue UML



Implémentation

Rien ne vaut un petit exemple simple et pratique pour mettre en œuvre ce pattern. Imaginons que nous avons des articles en vente et que nous avons également des clients qui vont être intéressés par ces objets.
Si le prix d’un article mis en vente varie, il faudrait que les clients puissent être informés de ce changement.

Voici l’implémentation que je propose pour ce problème.
Pour commencer, l’observer, c'est-à-dire l’interface qui va nous mettre à disposition une méthode update.

using System;

namespace DPObserver
{

/// ------------------------------------------------------------------
/// <summary>
/// Represents the observer object.
/// </summary>
/// ------------------------------------------------------------------
public interface IClient
{

/// ---------------------------------------------------------------
/// <summary>
/// The article has been updated.
/// </summary>
/// ---------------------------------------------------------------
void Update(DefaultArticle defaultArticle);

}
}

Ensuite, notre classe Client qui va implémenter cette interface

namespace DPObserver
{

/// ------------------------------------------------------------------
/// <summary>
/// Represents the concrete observer.
/// </summary>
/// ------------------------------------------------------------------
public class Client : IClient
{
private string _name = null;

/// ---------------------------------------------------------------
/// <summary>
/// Create a new client.
/// </summary>
/// ---------------------------------------------------------------
public Client(string name)
{
this._name = name;
}

/// ---------------------------------------------------------------
/// <summary>
/// Get the client's name.
/// </summary>
/// ---------------------------------------------------------------
public string Name
{
get { return this._name; }
}

/// ---------------------------------------------------------------
/// <summary>
///
/// </summary>
/// ---------------------------------------------------------------
public void Update(DefaultArticle defaultArticle)
{
Console.WriteLine("Client {0} notified! Article {1}: new price = {2}", this._name, defaultArticle.Name, defaultArticle.Price);
}
}
}

La partie ‘Observer’ est donc très simple. Passons maintenant à l’implémentation du sujet. On commence par la classe abstraite qui nous définies les méthodes ‘d’abonnements’.

namespace DPObserver
{

/// ------------------------------------------------------------------
/// <summary>
/// Represents the subject object.
/// </summary>
/// ------------------------------------------------------------------
public abstract class DefaultArticle
{
private List<IClient> _observers = new List<IClient>();
protected float _price = 0f;
protected string _name = String.Empty;

/// ---------------------------------------------------------------
/// <summary>
/// Get or set the price.
/// </summary>
/// ---------------------------------------------------------------
public float Price
{
get { return this._price; }
set
{
this._price = value;
this.NotifyObservers();
}
}

/// ---------------------------------------------------------------
/// <summary>
/// Get the name.
/// </summary>
/// ---------------------------------------------------------------
public string Name
{
get { return this._name; }
}

/// ---------------------------------------------------------------
/// <summary>
/// Attach an observer.
/// </summary>
/// <param name="client">The observer to attach.</param>
/// ---------------------------------------------------------------
public void Attach(IClient client)
{
if (!this._observers.Contains(client)) this._observers.Add(client);
}


/// ---------------------------------------------------------------
/// <summary>
/// Detach an observer.
/// </summary>
/// <param name="client">The observer to dettach.</param>
/// ---------------------------------------------------------------
public void Detach(IClient client)
{
if (this._observers.Contains(client)) this._observers.Remove(client);
}

/// ---------------------------------------------------------------
/// <summary>
/// Notify all observers.
/// </summary>
/// ---------------------------------------------------------------
protected void NotifyObservers()
{
foreach (IClient obs in this._observers) obs.Update(this);
}
}

}

Puis, pour terminé, notre Article qui est l’implémentation concrète

namespace DPObserver
{
/// ------------------------------------------------------------------
/// <summary>
/// Represents the concrete subject.
/// </summary>
/// ------------------------------------------------------------------
public class Article : DefaultArticle
{

/// ---------------------------------------------------------------
/// <summary>
/// Create a new article.
/// </summary>
/// <param name="name"></param>
/// <param name="price"></param>
/// ---------------------------------------------------------------
public Article(string name)
{
this._name = name;
}
}
}

Et voilà, on a déjà mis en place le mécanisme pour que notre client soit notifié des changements. Ecrivons quelques lignes des tests :

namespace DPObserver
{
public class Program
{

public static void Main(string[] args)
{

var article1 = new Article("CodeS-SourceS") { Price = 1234.50f };
var article2 = new Article("Livre C#") { Price = 432.10f };
var article3 = new Article("Abonnement MSDN") { Price = 12345.60f };
var article4 = new Article("Camion poubelle") { Price = 123.4f };
var article5 = new Article("Sifflet") { Price = 12f };

var client1 = new Client("Bidou");
var client2 = new Client("Nix");

article1.Attach(client1);
article1.Attach(client2);
article1.Price = 88.5f;
article1.Detach(client1);
article1.Price = 73.3f;

article2.Attach(client1);
article2.Attach(client2);
article2.Price = 400f;

article3.Attach(client1);
article3.Price = 14000f;

article5.Attach(client2);
article5.Price = 12f;

}
}
}

Les résultats sont bien ceux attendus :

Conclusions

Ce pattern est assez utilisé et pas très compliqué à mettre en place. Dans la réalité, le cas sera certainement plus complexe. On peut par exemple tout à fait imaginer que l’objet qui joue le rôle d’observateur soit en même temps le sujet d’un autre observerateur, et qu’on ait ainsi une chaîne entre les différents objets.


06 décembre 2007 21:11:18 :
mise en page
06 décembre 2007 21:14:28 :
Mise en page
  • signaler à un administrateur
    Commentaire de billou_13 le 07/12/2007 09:43:41

    Merci Bidou pour la source, expliqué et instructive.

    Certes, elle est simple, mais personne n'y pense quand le cas se présente. Alors que ce pattern pourrait résoudre bien des problèmes.

    A garder en tête pour le prochain développement,

  • signaler à un administrateur
    Commentaire de ecosmose le 27/01/2008 17:19:32

    Perso, un second code plus générique aurait été le bienvenu pour conserver de l'aspect conceptuel mais je vous note 10 pour saluer l'excellente initiative et la mise en application dans le code présent du design pattern Observer...

    Très utile lors de l'emploi de Factory pour associer les ojets observeur des observés...

    Utile dans l'emploi de Webservice (Serveur) pour gérer les abonnements aux ressources (sur la BD) utilisées par des observeurs (clients). Il permet d'intégrer avec souplesse et legereté les notifications de modifications des ressources paratagées en Base par plusieurs clients déconnectés ;-)...L'architecture décrite est , d'après mes recherches, seulement intégrée au Framework 3.0 et supérieure au sein de WCF...

    Un grand Merci et Bravo donc ;-)

  • signaler à un administrateur
    Commentaire de Yoteco le 15/02/2008 12:19:28

    Salut,

    Merci Dubuis ! Par contre tu as oublié la classe conteneur quand tu retourne l'objet (this) au observeur !

    Je t'ai mis 10 parce que t'es un bon type.

Ajouter un commentaire

Appels d'offres

Pub



CalendriCode

Mai 2008
LMMJVSD
   1234
567891011
12131415161718
19202122232425
262728293031 

Boutique

Boutique de goodies CodeS-SourceS