vendredi 22 novembre 2024

Observer - Event

 Le design pattern Observer est un modèle de conception comportemental qui permet à un objet, appelé sujet (subject), de notifier automatiquement ses dépendants, appelés observateurs (observers), lorsque son état change. Cela permet aux observateurs de rester synchronisés avec le sujet sans nécessiter de couplage direct entre eux.

Voici un exemple en C# illustrant le design pattern Observer :

```csharp

using System;

using System.Collections.Generic;

// Définition de l'interface de l'observateur

public interface IObserver

{

void Update(string message);

}

// Définition de l'interface du sujet

public interface ISubject

{

void Attach(IObserver observer);

void Detach(IObserver observer);

void Notify();

}

// Implémentation de l'observateur

public class ConcreteObserver : IObserver

{

private string _name;

public ConcreteObserver(string name)

{

_name = name;

}

public void Update(string message)

{

Console.WriteLine($"Observer {_name} received message: {message}");

}

}

// Implémentation du sujet

public class ConcreteSubject : ISubject

{

private List<IObserver> _observers = new List<IObserver>();

private string _message;

public void Attach(IObserver observer)

{

_observers.Add(observer);

}

public void Detach(IObserver observer)

{

_observers.Remove(observer);

}

public void Notify()

{

foreach (var observer in _observers)

{

observer.Update(_message);

}

}

public void ChangeMessage(string newMessage)

{

_message = newMessage;

Notify();

}

}

class Program

{

static void Main(string[] args)

{

// Création des observateurs

var observer1 = new ConcreteObserver("Observer 1");

var observer2 = new ConcreteObserver("Observer 2");

// Création du sujet

var subject = new ConcreteSubject();

// Attachement des observateurs au sujet

subject.Attach(observer1);

subject.Attach(observer2);

// Changement de l'état du sujet

subject.ChangeMessage("Hello World!");

// Détachement d'un observateur du sujet

subject.Detach(observer2);

// Changement de l'état du sujet

subject.ChangeMessage("Goodbye!");

Console.ReadLine();

}

}

```

Dans cet exemple, nous avons un sujet (`ConcreteSubject`) qui maintient une liste d'observateurs (`ConcreteObserver`). Lorsque l'état du sujet change, il notifie automatiquement tous ses observateurs en appelant leur méthode `Update`. Les observateurs, à leur tour, réagissent au changement d'état en exécutant une action spécifique, dans cet exemple, en affichant le message reçu à la console.


Differents entre Observer et Event

En C#, les design patterns Observer et les événements (Event) peuvent sembler similaires car ils permettent tous deux à un objet d’être notifié des changements d’un autre objet. Cependant, ils diffèrent en termes d'implémentation, d'objectif et d'applicabilité. Voici une explication des deux et de leur différence, suivie de leur utilité pour le multithreading.


1. Observer Pattern

Définition :

Le design pattern Observer est un modèle de conception où un objet, appelé sujet (subject), maintient une liste d'observateurs qui veulent être informés des changements d'état du sujet. Les observateurs s'enregistrent auprès du sujet pour recevoir des notifications.

Caractéristiques :

  • Implémenté généralement via des interfaces ou des abstractions.
  • Les relations entre le sujet et les observateurs sont explicites.
  • Plus flexible : vous pouvez facilement personnaliser ou étendre son fonctionnement.
  • Nécessite d'écrire plus de code manuellement.

Exemple en C# :

using System;
using System.Collections.Generic;

public interface IObserver
{
    void Update(string message);
}

public class Subject
{
    private List<IObserver> _observers = new List<IObserver>();

    public void Attach(IObserver observer) => _observers.Add(observer);
    public void Detach(IObserver observer) => _observers.Remove(observer);

    public void Notify(string message)
    {
        foreach (var observer in _observers)
        {
            observer.Update(message);
        }
    }
}

public class ConcreteObserver : IObserver
{
    public void Update(string message) => Console.WriteLine($"Received: {message}");
}

public class Program
{
    public static void Main()
    {
        var subject = new Subject();
        var observer1 = new ConcreteObserver();
        var observer2 = new ConcreteObserver();

        subject.Attach(observer1);
        subject.Attach(observer2);

        subject.Notify("Hello Observers!");
    }
}


2. Event en C#

Définition :

Un événement en C# est une abstraction intégrée du langage pour la communication entre objets. Il repose sur les délégués et permet à un objet (éditeur) de notifier d'autres objets (abonnés) d'un événement spécifique.

Caractéristiques :

  • Moins de code nécessaire grâce à la syntaxe native de C#.
  • Plus limité : les abonnés ne peuvent pas contrôler directement l'objet source (éditeur).
  • Idéal pour des scénarios simples où il suffit de notifier des changements.

Exemple en C# :

using System;

public class Publisher
{
    public event EventHandler<string> OnMessage;

    public void Notify(string message)
    {
        OnMessage?.Invoke(this, message);
    }
}

public class Subscriber
{
    public void Subscribe(Publisher publisher)
    {
        publisher.OnMessage += HandleMessage;
    }

    private void HandleMessage(object sender, string message)
    {
        Console.WriteLine($"Received: {message}");
    }
}

public class Program
{
    public static void Main()
    {
        var publisher = new Publisher();
        var subscriber = new Subscriber();

        subscriber.Subscribe(publisher);

        publisher.Notify("Hello Events!");
    }
}


Différences principales :

Aspect Observer Pattern Event (C#)
Implémentation Basée sur des abstractions (interfaces, classes). Basée sur les délégués et event.
Flexibilité Plus personnalisable (comportement des observateurs). Plus simple et direct, mais limité.
Encapsulation Les observateurs connaissent le sujet. Les abonnés ne connaissent que l’événement.
Couplage Plus fortement couplé. Moins couplé grâce aux délégués.


Utilité pour le multithreading

  • Observer Pattern :

    • Peut nécessiter une synchronisation manuelle pour protéger la liste des observateurs et éviter des problèmes de thread.
    • Complexe à gérer dans des contextes fortement concurrents.
  • Event en C# :

    • Les événements fonctionnent bien dans un environnement multithread, car les abonnés sont gérés via des délégués.
    • Toutefois, pour éviter les conditions de course, il est recommandé d'utiliser Interlocked.CompareExchange pour l'abonnement ou d'assurer un accès thread-safe via des locks.

Exemple pour gérer des événements thread-safe :

public class ThreadSafePublisher
{
    private event EventHandler<string> _onMessage;

    public event EventHandler<string> OnMessage
    {
        add { lock (this) { _onMessage += value; } }
        remove { lock (this) { _onMessage -= value; } }
    }

    public void Notify(string message)
    {
        _onMessage?.Invoke(this, message);
    }
}


Conclusion

  • Observer Pattern est préférable lorsque vous voulez plus de contrôle sur la logique des notifications ou lorsque vous travaillez dans des systèmes non .NET.
  • Events sont plus naturels dans l'écosystème C#, surtout pour des scénarios simples ou des applications multithread.


Aucun commentaire:

Enregistrer un commentaire