web-dev-qa-db-fra.com

Pourquoi les gens utilisent des bus de messages / événements dans leur code?

Je pense que vous avez entendu parler des bus de messages/événements, c'est le seul endroit où tous les événements du système circulent. Des architectures similaires se trouvent dans les cartes mères et les réseaux LAN des ordinateurs. C'est une bonne approche pour les cartes mères et les réseaux car elle réduit le nombre de fils, mais est-elle bonne pour le développement logiciel? Nous n'avons pas de restrictions comme l'électronique.

La mise en œuvre la plus simple du bus de messages/bus d'événements peut être comme:

class EventBus {
    void addListener(EventBusListener l}{...}
    void fireEvent(Event e) {...}
}

La publication d'événements se fait avec bus.fireEvent (événement), la réception de messages est activée par bus.addListener (écouteur). De telles architectures sont parfois utilisées pour le développement de logiciels, par exemple MVP4G implémente un bus de messages similaire pour GWT.

Projets actifs:

Projets dormants/morts:

C'est juste le modèle d'observateur (écouteur) populaire fait `` globalement '' - chaque objet dans le système peut écouter chaque message, et je pense que c'est mauvais, il rompt le principe d'encapsulation (chaque objet sait tout) et le principe de responsabilité unique (par exemple quand certains objets ont besoin d'un nouveau type de message, le bus d'événements doit souvent être changé par exemple pour ajouter une nouvelle classe Listener ou une nouvelle méthode dans la classe Listener).

Pour ces raisons, je pense que pour la plupart des logiciels, le modèle Observer est meilleur que le bus d'événements. Que pensez-vous du bus d'événements, est-ce que cela a du bon sens pour des applications typiques?

EDIT: Je ne parle pas de "grandes" solutions d'entreprise comme ESB - elles peuvent être utiles (de plus, ESB offre beaucoup, bien plus qu'un simple bus d'événements). Je demande l'utilité de l'utilisation du bus de messages en 'normal' Java pour la connexion objet à objet - certaines personnes le font, vérifiez les liens ci-dessus. Le bus d'événements est probablement la meilleure solution pour la communication de téléphone à téléphone ou la communication d'ordinateur à ordinateur car chaque téléphone (ou ordinateur) d'un réseau peut généralement se parler et le bus réduit le nombre de fils. Mais les objets se parlent rarement - combien de collaborateurs un l'objet peut avoir - 3, 5?

60
iirekm

Certaines personnes l'aiment parce que c'est l'incarnation du modèle de façade ou modèle de médiateur . Il centralise les activités transversales comme la journalisation, les alertes, la surveillance, la sécurité, etc.

Certaines personnes ne l'aiment pas, car il s'agit souvent d'un point de défaillance de Singleton. Tout le monde doit le savoir.

26
duffymo

J'envisage d'utiliser un bus d'événements en mémoire pour mon code Java Java normal et ma justification est la suivante)

Chaque objet du système peut écouter chaque message, et je pense que c'est mauvais, cela rompt le principe d'encapsulation (chaque objet sait tout)

Je ne sais pas si cela est vraiment vrai, je classe doit commencer par s'inscrire avec le bus d'événements, semblable au modèle d'observateur, une fois qu'une classe s'est inscrite avec le bus d'événements, seules les méthodes qui ont la signature et l'annotation appropriées sont notifiées .

et principe de responsabilité unique (par exemple, lorsqu'un objet a besoin d'un nouveau type de message, le bus d'événements doit souvent être modifié, par exemple pour ajouter une nouvelle classe d'écoute ou une nouvelle méthode dans la classe d'écoute).

Je suis totalement en désaccord avec

le bus d'événement doit souvent être changé

Le bus d'événement n'est jamais changé

Je suis d'accord avec

add a new Listener class or a new method in the Listener class

Comment cela brise-t-il la SRP?, Je peux avoir un BookEventListener qui s'abonne à tous les événements relatifs à mon entité Book, et oui je peux ajouter des méthodes à cette classe mais cette classe est toujours cohérente ...

Pourquoi ai-je l'intention de l'utiliser? Cela m'aide à modéliser le "quand" de mon domaine ....

Habituellement, nous entendons quelque chose comme envoyer un mail "quand" le livre est acheté

nous allons écrire

book.purchase();
sendEmail()

Ensuite, on nous dit d'ajouter un journal d'audit lorsqu'un livre est acheté, nous allons à l'extrait ci-dessus

book.purchase();
sendEmail();
**auditBook();**

Juste là OCP violé

Je préfère

book.purchase();
EventBus.raiseEvent(bookPurchasedEvent);

Continuez ensuite à ajouter des gestionnaires selon vos besoins. Ouvert pour l'extension Fermé pour la modification

Merci

66
Sudarshan

Je l'utilise beaucoup en JavaScript. Il peut y avoir tellement de widgets différents que tous doivent faire une sorte d'action chaque fois que quelque chose se passe - il n'y a pas de véritable hiérarchie de propriété des objets. Au lieu de transmettre des références de chaque objet à chaque objet, ou simplement de rendre chaque objet global, lorsque quelque chose d'important se produit à l'intérieur d'un widget particulier, je peux simplement publier "/ thisWidget/somethingHappened" - au lieu de remplir ce widget avec toutes sortes de code spécifique à l'API d'autres widgets. J'ai une seule classe qui contient tout le "câblage" ou "plubming" comme ils aiment l'appeler dans le framework Java Spring. Cette classe contient des références à tous mes widgets, et a tout le code de ce qui se passe après chaque événement se déclenche.

Il est centralisé, facile d'accès et de maintenance, et si une chose change ou si je veux qu'un nouveau processus se produise sur un événement spécifique, je n'ai pas à parcourir chaque classe/objet/widget pour essayer de trouver où quelque chose est en cours de traitement. Je peux simplement aller dans ma classe "opérateur" - celle qui gère tout le "câblage" lorsqu'un événement particulier se produit, et voir toutes les répercussions de cet événement. Dans ce système, chaque widget individuel est complètement indépendant de l'API des autres widgets. Il publie simplement ce qui lui est arrivé ou ce qu'il fait.

16
Bal

J'ai du mal à comprendre ce que vous demandez vraiment dans votre question. Vous donnez un exemple d'un bus d'événements simple qui est en fait juste Observable avec un nom différent, puis vous dites;

Pour ces raisons, je pense que pour la plupart des logiciels, le modèle Observer est meilleur que le bus d'événements. Que pensez-vous du bus d'événements, est-ce que cela a du bon sens pour des applications typiques?

..mais étant donné votre exemple, ce sont les mêmes. Cela me fait me demander si vous avez déjà utilisé quelque chose comme un bus de service d'entreprise. Au niveau de base, un ESB fait logiquement la même chose que le modèle d'observateur, mais les produits commerciaux ajoutent beaucoup, beaucoup plus. C'est comme un bus d'événement sur les stéroïdes. Ce sont des produits logiciels complexes et offrent;

Collecte des messages
Générez des événements en écoutant différents points de terminaison. Le point de terminaison peut être un écouteur (tel qu'un serveur HTTP), un système de messagerie (tel que JMS), une base de données ou à peu près tout ce que vous voulez.

Acheminement des messages
Prenez votre événement et envoyez-le à un/plusieurs points de terminaison. Le routage peut être assez intelligent, le bus peut acheminer le message en fonction du type de message, du contenu du message ou de tout autre critère. Le routage peut être intelligent et dynamique.

Transformation du message
Transforme votre message dans un autre format, cela peut être aussi simple que de XML en JSON ou d'une ligne sur une table de base de données en une requête HTTP. La transformation peut se produire dans les données elles-mêmes, par exemple en échangeant des formats de date.

Enrichissement des données
Ajoute ou modifie des données dans votre message en appelant des services en cours de route. Par exemple, si un message contient un code postal, le bus peut utiliser un service de recherche de code postal pour ajouter des données d'adresse.

..et beaucoup, beaucoup plus. Lorsque vous commencez à regarder les détails, vous pouvez vraiment commencer à voir pourquoi les gens utilisent ces choses.

14
Qwerky

Parce que cela peut être une étape importante dans la façon de découpler les modules d'application à une architecture basée sur les services .

Donc, dans votre cas, si vous n'avez pas l'intention de découpler les modules de votre application en services isolés, l'implémentation native du modèle d'observateur en fera un solution plus simple.

Mais si vous voulez construire, disons une architecture de micro-services le bus d'événement permettra d'obtenir les avantages de ce style d'architecture pour que vous puissiez par exemple mettre à jour et déployer seulement une partie de votre application sans affecter les autres, car ils sont simplement connectés via le bus d'événements.

Donc, la principale question ici est le niveau souhaité de découplage des composants d'application .

Quelques références à ce sujet:

4
brunocrt

Une bonne analogie est celle d'un central téléphonique, où chaque combiné peut composer avec n'importe quel autre combiné. Un combiné compromis peut se connecter à d'autres conversations. Le contrôle du programme s'écoule comme des fils (complexité cyclomatique n'importe qui!). Cela est similaire à l'exigence d'avoir une connexion/un support physique entre deux points d'extrémité. Il en est ainsi pour N combinés au lieu d'avoir des flux NC2 (logique combinatoire) pour chaque nouveau combiné, nous avons tendance à obtenir N flux.

Une réduction de la complexité implique un code facile à comprendre. Commençons par les points importants que vous avez mis en évidence: 1. Connaissance globale 2. Modifications intrusives.

Connaissance globale: Considérez l'événement de message comme une enveloppe. Du point de vue du gestionnaire d'événements/expéditeur, aucune donnée n'est exposée, elle voit une enveloppe (sauf si une classe dérivée essaie de faire une inspection en utilisant des vérifications "instanceof"). Dans une bonne conception OOP, cela ne se produirait jamais.

Modifications intrusives: au lieu d'avoir une approche d'écoute spécifique à l'événement, on peut utiliser une approche globale de gestion des événements. En tant que tel, nous avons un type d'événement global (sur lequel les données sont piggy back et down-casted). Cela ressemble beaucoup au modèle PropertyBeanSupport en Java. Avec un seul type d'événement, nous devons avoir un seul type d'expéditeur et d'écouteur. Cela implique que vous n'avez pas besoin de modifier le bus/écouteurs chaque fois que vous voyez quelque chose de nouveau. Le laid down-casting peut être apaisé en utilisant un modèle d'adaptateur (veuillez ne pas commencer un autre niveau de devis de redirection!). Les programmeurs peuvent écrire Assembly dans n'importe quelle langue. Le besoin de bon sens et d'intelligence ne peut donc pas être remplacé. Tout ce que j'ai l'intention de dire, c'est que cela peut être un outil efficace.

Les récepteurs d'événements réels peuvent facilement utiliser les écouteurs (composition/proxy). Dans une telle base de code Java Java, les auditeurs ressembleraient à des déclarations de classe interne autonomes (avec un avertissement inutilisé étant signalé dans certains IDE). Cela tient à ce que deux joueurs sur la plage jouent à un jeu de balle, les joueurs ne réagissent pas jusqu'à ce qu'ils voient le ballon.

'@duffymo' souligne un autre aspect intéressant: 'Single point of failure'. Cela pourrait/pourrait en théorie affecter tout objet résidant en mémoire (RAM) et non spécifique aux MessageHandlers.

2
questzen

À titre d'exemple pratique, notre application se synchronise avec un service Web toutes les x minutes, et si de nouvelles données sont reçues, nous devons mettre à jour l'interface graphique. Maintenant, comme SyncAdapter s'exécute sur un thread d'arrière-plan, vous ne pouvez pas simplement pointer vers une vue de texte et modifier ses propriétés, vous devez faire bouillonner un événement. Et la seule façon de vous assurer que vous interceptez cet événement est si vous avez un objet partagé (statique, singleton) passant cet événement pour que les abonnés le gèrent.

1
Captain Kenpachi