Event Bus et le pattern Observer en C# (.NET) : de la théorie à la pratique
Dans le développement moderne en C# (.NET), l'un des principes clés est le couplage faible (loose coupling) entre les composants du système. Le pattern Observer (Observateur) et son évolution — l'Event Bus (Bus d'événements) — offrent un mécanisme élégant pour organiser l'interaction entre objets sans dépendances directes. Dans cet article, nous analyserons en détail comment implémenter un Event Bus en C# (.NET), examinerons son architecture et fournirons des exemples pratiques.
Qu'est-ce que le pattern Observer ?
Le pattern Observer définit une relation « un à plusieurs » entre objets : lorsqu'un objet (le sujet) modifie son état, tous les objets qui en dépendent (les observateurs) sont automatiquement notifiés et mis à jour. En C#, ce pattern est traditionnellement implémenté via les événements (event) et les délégués.
Problème de l'implémentation classique
Bien que les événements intégrés de C# fonctionnent bien, ils présentent des limitations :
- Lien direct : l'éditeur doit connaître explicitement les abonnés.
- Complexité du désabonnement : si un abonné oublie de se désabonner, cela provoque une fuite mémoire.
- Flexibilité limitée : il est difficile d'organiser un traitement asynchrone ou un filtrage des événements.
Qu'est-ce qu'un Event Bus ?
Un Event Bus est un bus centralisé (médiateur) qui implémente le pattern Publisher-Subscriber (Éditeur-Abonné). Contrairement à l'Observer classique, l'éditeur et l'abonné ne se connaissent pas du tout. Ils communiquent uniquement via le bus :
- L'éditeur envoie un message (événement) dans le bus.
- Le bus trouve tous les abonnés à ce type d'événement et les notifie.
- L'abonné s'enregistre pour un type d'événement spécifique et le traite.
Avantages de l'Event Bus
- Couplage faible : les composants ne dépendent pas les uns des autres.
- Évolutivité : il est facile d'ajouter de nouveaux abonnés.
- Testabilité : on peut remplacer le bus par des mocks.
- Asynchronisme : on peut traiter les événements dans des threads d'arrière-plan.
Implémentation d'un Event Bus en C# (.NET)
Examinons une implémentation simple mais fonctionnelle. Créons une classe EventBus qui stockera un dictionnaire d'abonnés.
public interface IEventBus{ void Publish<TEvent>(TEvent eventData) where TEvent : class; IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : class;}
public class EventBus : IEventBus{ private readonly Dictionary<Type, List<Delegate>> _subscribers = new(); private readonly object _lock = new();
public void Publish<TEvent>(TEvent eventData) where TEvent : class { List<Delegate> handlers; lock (_lock) { if (!_subscribers.TryGetValue(typeof(TEvent), out var list)) return; handlers = new List<Delegate>(list); }
foreach (var handler in handlers) { if (handler is Action<TEvent> action) action(eventData); } }
public IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : class { lock (_lock) { if (!_subscribers.ContainsKey(typeof(TEvent))) _subscribers[typeof(TEvent)] = new List<Delegate>(); _subscribers[typeof(TEvent)].Add(handler); }
return new Unsubscriber(() => { lock (_lock) { if (_subscribers.TryGetValue(typeof(TEvent), out var list)) list.Remove(handler); } Aussi dans la bibliothèque
Files d'attente de tâches pour C++ : implémentation et utilisation
Armadillo C++ : guide complet avec exemples pratiques
clinic.js — Surveillance des applications TypeScript
Travailler avec XML en C++ : bibliothèques PugiXML et RapidXML