Aide-mémoire, Head First Design Patterns, chapitre 2

Observer

Un objet prévient tous ses abonnés quand son état change. Il ne connaît d'eux que le contrat, et chacun peut s'abonner ou se désabonner pendant l'exécution.

« Définir une dépendance un-à-plusieurs entre des objets, de sorte que, quand un objet change d'état, tous ceux qui en dépendent soient prévenus et mis à jour automatiquement. » Gamma, Helm, Johnson et Vlissides, Design Patterns, 1994

Observer appliqué au panier d'une boutique Panier garde une liste d'observateurs et envoie à chacun un EtatPanier après chaque changement. Badge, Recap et Sauvegarde implémentent l'interface ObservateurPanier. Un nouvel abonné, Fidelite, s'ajouterait par un appel à abonner sans modifier Panier. Panier #observateurs: […] abonner(o) desabonner(o) #notifier() * «interface» ObservateurPanier panierModifie(etat: EtatPanier) Badge nombreArticles Recap totalCentimes Sauvegarde lignes Fidelite demain ? Le sujet.Il garde la listede ses abonnéset les prévient tous. prévient Le contrat.Une méthodepour tous. implémentent Les observateurs.Chacun lit dans etatce qui l'intéresse. Un abonné de plus ? Un appel à abonner().Panier ne change pas.

Les trois rôles

Le sujet, Panier
Il garde la liste de ses observateurs. Après chaque changement, dans ajouter comme dans vider, il appelle #notifier, qui envoie l'état à chacun.
Le contrat, ObservateurPanier
Une seule méthode, panierModifie(etat), que le sujet appelle sur chaque abonné.
Les observateurs, Badge, Recap, Sauvegarde
Chacun réagit à sa façon. Aucun ne connaît les autres.

Le code qui assemble l'application branche les abonnés de l'extérieur avec panier.abonner(badge). Il peut aussi en retirer un avec panier.desabonner(badge).

Le livre compare le sujet à un éditeur de journal, et les observateurs à ses abonnés.

Le reconnaître

Un changement doit déclencher plusieurs réactions sans rapport entre elles, et leur liste varie. Le signal le plus courant est une méthode qui appelle à la suite des objets étrangers à son travail. Dans le panier de départ, ajouter mettait à jour le badge, le récapitulatif et la barre de livraison offerte.

Avec un seul destinataire qui ne change pas, un appel direct reste plus simple à suivre.

Push ou pull

Le panier de l'exercice pousse (push) une photo de son état, EtatPanier, qui contient le nombre d'articles, le total et les lignes. Chaque observateur y lit ce qui l'intéresse. Un observateur qui aurait besoin d'une autre donnée obligerait à enrichir cette photo.

En pull, le sujet envoie sa propre référence, panierModifie(panier), et chaque observateur appelle les méthodes dont il a besoin. L'observateur dépend alors des méthodes publiques du sujet.

Le principe du chapitre

« Efforcez-vous de coupler faiblement les objets qui interagissent. » Panier connaît ObservateurPanier et ignore Badge. On ajoute, retire ou remplace un observateur sans modifier une ligne du panier.

Les principes du chapitre 1 reviennent aussi. Le panier programme pour une interface, et il compose une liste d'observateurs.

Classe ou fonction

Quand le contrat tient en une méthode, l'observateur peut être une simple fonction. abonner renvoie alors la fonction qui désabonne, et l'appelant n'a rien d'autre à garder : const arreter = panier.abonner(majBadge), puis arreter().

Dans le code web

addEventListener abonne une fonction aux événements d'un élément du DOM, qui joue le rôle du sujet. removeEventListener ou un AbortController la désabonnent.

Les stores de Svelte et de Redux exposent subscribe, qui renvoie la fonction de désabonnement. L'EventEmitter de Node applique le même pattern avec on, off et emit. Les signaux d'Angular et de Svelte 5 créent ces abonnements tout seuls quand un effet lit une valeur.

Le piège

Un observateur oublié reste en mémoire et continue de réagir. Un composant qui s'abonne doit donc se désabonner quand il disparaît, par exemple dans onDestroy, dans la fonction renvoyée par $effect ou avec controller.abort().

À vous

Strategy et Observer ont tous les deux une interface et plusieurs classes qui l'implémentent. Qu'est-ce qui les distingue ?

Voir la réponse

Le client de Strategy reçoit une seule variante, choisie de l'extérieur, et lui confie un calcul dont il attend le résultat. Le sujet d'Observer prévient tous ses abonnés après un changement, sans rien attendre en retour.