Patron Observateur
Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy. Leçon 68 sur 87.
Le pattern Observer est un patron de conception comportemental qui établit une relation un-à-plusieurs entre les objets. Lorsqu’un objet (le sujet) change d’état, toutes ses dépendances (les observateurs) sont automatiquement informées et mises à jour. Imaginez cela comme un abonnement à une newsletter : les abonnés reçoivent des mises à jour chaque fois qu’un nouveau contenu est publié.
Le modèle implique deux composants principaux : un sujet qui gère une liste d’observateurs et les informe des changements, ainsi que des observateurs qui définissent une méthode de mise à jour pour répondre aux notifications :
import java.util.ArrayList;
import java.util.List;
interface Observer {
void update(String message);
}
class NewsPublisher {
private List<Observer> subscribers = new ArrayList<>();
public void subscribe(Observer observer) {
subscribers.add(observer);
}
public void unsubscribe(Observer observer) {
subscribers.remove(observer);
}
public void publish(String news) {
for (Observer subscriber : subscribers) {
subscriber.update(news);
}
}
}
class EmailSubscriber implements Observer {
private String email;
public EmailSubscriber(String email) {
this.email = email;
}
public void update(String message) {
System.out.println("Email to " + email + ": " + message);
}
}Lorsque l’éditeur publie des actualités, tous les abonnés sont automatiquement informés :
NewsPublisher publisher = new NewsPublisher();
publisher.subscribe(new EmailSubscriber("alice@mail.com"));
publisher.subscribe(new EmailSubscriber("bob@mail.com"));
publisher.publish("Breaking news!");
// Sortie :
// Email à alice@mail.com : Breaking news!
// Email à bob@mail.com : Breaking news!Le modèle Observer favorise un couplage faible : le sujet n’a pas besoin de connaître les classes concrètes de ses observateurs, mais seulement de savoir qu’ils implémentent l’interface Observer. Cela facilite l’ajout de nouveaux types d’observateurs sans modifier le sujet.
Défi
FacileConstruisons un système d’alerte de cours boursiers utilisant le modèle Observer ! Vous allez créer un système dans lequel un téléscripteur boursier informe plusieurs investisseurs chaque fois que le cours de l’action change, permettant à chaque investisseur de réagir aux mises à jour du cours à sa manière.
Vous organiserez votre code dans quatre fichiers :
Observer.java: définissez l’interfaceObserverque tous les investisseurs implémenteront. Elle doit déclarer une seule méthodeupdate(String stockName, double price)que les observateurs utilisent pour recevoir des notifications concernant les changements de cours.StockTicker.java: créez la classe sujet qui conserve une liste d’observateurs et les informe des changements de cours. VotreStockTickerdoit avoir :Un champ String privé pour le nom de l’action (défini via le constructeur).
Un champ double privé pour le cours actuel (initialement à 0).
Une liste privée pour stocker les observateurs abonnés.
Une méthode
subscribe(Observer observer)qui ajoute un observateur à la liste.Une méthode
unsubscribe(Observer observer)qui supprime un observateur de la liste.Une méthode
setPrice(double price)qui met à jour le cours, puis informe tous les observateurs en appelant leur méthodeupdateavec le nom de l’action et le nouveau cours.Investors.java: créez deux types différents d’investisseurs qui implémentent l’interfaceObserver:DayTrader: possède un champ name privé défini via le constructeur. Lorsqu’il est mis à jour, il affiche[name] received alert: [stockName] is now $[price] - Making quick trade!LongTermInvestor: possède un champ name privé défini via le constructeur. Lorsqu’il est mis à jour, il affiche[name] received alert: [stockName] is now $[price] - Holding steady.Formatez le cours avec deux décimales.
Main.java: assemblez votre système d’observateurs ! Vous recevrez trois entrées : le nom de l’action (String), la première mise à jour du cours (double) et la deuxième mise à jour du cours (double).Créez un
StockTickeravec le nom d’action fourni. Créez unDayTradernommé"Alice"et unLongTermInvestornommé"Bob", puis abonnez-les tous deux au téléscripteur.Définissez le cours sur la première valeur d’entrée (tous les observateurs sont informés). Désabonnez ensuite Alice. Enfin, définissez le cours sur la deuxième valeur d’entrée (seul Bob doit être informé cette fois).
Vous recevrez trois entrées dans l’ordre suivant : le nom de l’action (String), le premier cours (double), le deuxième cours (double).
Ce défi démontre la puissance du modèle Observer : le StockTicker ne sait rien des types spécifiques d’investisseurs. Il sait simplement qu’ils implémentent Observer. Lorsque vous désabonnez Alice, elle cesse de recevoir les mises à jour tandis que Bob continue d’être informé. Ce couplage faible facilite l’ajout de nouveaux types d’investisseurs sans modifier le téléscripteur !
Essayez vous-même
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Lire les entrées
String stockName = scanner.nextLine();
double firstPrice = scanner.nextDouble();
double secondPrice = scanner.nextDouble();
// TODO: Créer un StockTicker avec le nom d'action donné
// TODO: Créer un DayTrader nommé "Alice"
// TODO: Créer un LongTermInvestor nommé "Bob"
// TODO: Abonner Alice et Bob au ticker
// TODO: Définir le prix à firstPrice (les deux observateurs sont notifiés)
// TODO: Désabonner Alice
// TODO: Définir le prix à secondPrice (seul Bob est notifié)
scanner.close();
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesChamps (Attributs)Méthode constructeurSurcharge de constructeurRécapitulatif - Calculatrice simple4Héritage
Héritage de base (extends)Le mot-clé superRedéfinition de méthode (@Override)Chaînage de constructeursLa classe ObjectHéritage simple et multiniveauPourquoi pas d'héritage multiple de classesRécapitulatif - Hiérarchie des employés7Méthodes spéciales et classe Object
Méthode toString()equals() et hashCode()Méthode clone()compareTo() et ComparableInterface ComparatorRécapitulatif - Tri personnalisé2Modificateurs d'accès et Encapsulation
Aperçu des niveaux d'accèsMéthodes Getter et SetterMasquage d'informationsLe mot-clé finalRécapitulatif - Gestionnaire de compte bancaire5Polymorphisme
Bases de la surcharge de méthodesRedéfinition de méthodes (Run-Time)Upcasting et DowncastingL'opérateur instanceofClasses et méthodes abstraitesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageAgrégation vs CompositionClasses internes, imbriquées et anonymesEnums et méthodes d'EnumRecords (Java 16+)Classes scellées (Java 17+)11Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron MonteurPatron ObservateurPatron Stratégie3Propriétés de classe et membres statiques
Variables d'instance vs variables statiquesMéthodes statiquesBlocs statiquesConstantes (static final)Récapitulatif - Compteur et utilitaire6Interfaces et Classes Abstraites
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesDefault et Static dans les InterfacesClasses Abstraites vs InterfacesInterfaces FonctionnellesRécapitulatif - Système de Paiement9La généricité
Introduction à la généricitéClasses génériquesMéthodes génériquesParamètres de type bornésWildcards (?, extends, super)Récapitulatif - Conteneur générique12Patrons de conception, partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositePatron ItérateurEntraînez-vous par vous-même : Compilateur Java en ligne