Event Bus et le pattern Observer en C# (.NET) : implémentation pour les microservices et l'interface graphique

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Event Bus et le pattern Observer en C# (.NET) : de la théorie à l'implémentation

\n\n

Dans le développement moderne en C# (.NET), il est souvent nécessaire d'organiser l'interaction entre les composants d'un système tout en préservant leur indépendance. Le pattern Observer et son évolution — l'Event Bus (Bus d'événements) — sont des outils clés pour implémenter le couplage faible (loose coupling). Dans cet article, nous analyserons le fonctionnement de ces mécanismes et créerons une implémentation simple mais fonctionnelle d'un Event Bus en C#.

\n\n

Pattern Observer : approche classique

\n\n

Le pattern Observer définit une relation "un à plusieurs" entre les objets : lorsqu'un objet (l'éditeur) change d'état, tous les objets dépendants (les abonnés) sont automatiquement notifiés. Dans .NET, ce pattern est intégré via les événements (event) et les délégués.

\n\n

Inconvénients de l'implémentation classique :

\n
    \n
  • Dépendance directe de l'abonné envers l'éditeur (nécessité de stocker une référence vers l'objet).
  • \n
  • Complexité de gestion des abonnements dans les grands systèmes.
  • \n
  • Problèmes de threads (le multithreading nécessite une synchronisation supplémentaire).
  • \n
\n\n

Event Bus : médiateur centralisé

\n\n

L'Event Bus résout ces problèmes en agissant comme un médiateur central. Au lieu de s'abonner directement à un objet spécifique, les composants s'enregistrent dans le bus d'événements. Les éditeurs publient des événements dans le bus, et le bus les distribue à tous les abonnés. Cela implémente le pattern Pub/Sub (Publish/Subscribe).

\n\n

Avantages de l'Event Bus :

\n
    \n
  • Couplage faible : les éditeurs et les abonnés ne se connaissent pas mutuellement.
  • \n
  • Extensibilité : il est facile d'ajouter de nouveaux abonnés.
  • \n
  • Polyvalence : adapté aux interfaces graphiques (WPF/WinForms), aux microservices et aux jeux (Unity).
  • \n
\n\n

Implémentation d'un Event Bus en C# (.NET)

\n\n

Nous allons créer une implémentation de base d'un Event Bus qui prend en charge le traitement asynchrone et les événements typés. Pour cela, nous utiliserons l'interface IEvent et la classe générique EventBus.

\n\n

Étape 1 : Définir les types de base.

\n
// Interface de base pour tous les événements\npublic interface IEvent { }\n\n// Exemple d'événement - message utilisateur\npublic class UserCreatedEvent : IEvent\n{\n    public int UserId { get; }\n    public string Email { get; }\n\n    public UserCreatedEvent(int userId, string email)\n    {\n        UserId = userId;\n        Email = email;\n    }\n}
\n\n

Étape 2 : Créer le bus d'événements.

\n
using System;\nusing System.Collections.Concurrent;\nusing System.Threading.Tasks;\n\npublic class EventBus\n{\n    // Stockage des abonnés : clé - type d'événement, valeur - liste des gestionnaires\n    private readonly ConcurrentDictionary<Type, ConcurrentBag<object>> _subscribers = new();\n\n    // Abonnement à un événement\n    public void Subscribe<TEvent>(Func<TEvent, Task> handler) where TEvent : IEvent\n    {\n        var eventType = typeof(TEvent);\n        var handlers = _subscribers.GetOrAdd(eventType, _ => new ConcurrentBag<object>());\n        handlers.Add(handler);\n    }\n\n    // Désabonnement (simplifié - supprime tous les gestionnaires de ce type)\n    public void Unsubscribe<TEvent>() where TEvent : IEvent\n    {\n        _subscribers.TryRemove(typeof(TEvent), out _);\n    }\n\n    // Publication d'un événement (asynchrone)\n    public async Task PublishAsync<TEvent>(TEvent eventData) where TEvent : IEvent\n    {\n        if (!_subscribers.TryGetValue(typeof(TEvent), out var handlers))\n            return;\n\n        foreach (var handler in handlers)\n        {\n            if (handler is Func<TEvent, Task> typedHandler)\n            {\n                await typedHandler(eventData);\n            }\n        }\n    }\n}
\n\n

Étape 3 : Utilisation dans l'application.

\n
public class                    

Recommendations