Le modèle Observer en Java

Le modèle Observer en Java

1. Vue d'ensemble

Dans cet article, nous allons décrire le modèle Observer et examiner quelques alternatives d'implémentation Java.

2. Quel est le modèle d'observateur?

Observer est un modèle de conception comportemental. Il spécifie la communication entre les objets:observable etobservers. An observable is an object which notifies observers about the changes in its state.

Par exemple, une agence de presse peut notifier les chaînes lorsqu'elle reçoit des nouvelles. Recevoir des informations est ce qui modifie l'état de l'agence de presse et entraîne la notification des chaînes.

Voyons comment nous pouvons le mettre en œuvre nous-mêmes.

Tout d'abord, définissons la classeNewsAgency:

public class NewsAgency {
    private String news;
    private List channels = new ArrayList<>();

    public void addObserver(Channel channel) {
        this.channels.add(channel);
    }

    public void removeObserver(Channel channel) {
        this.channels.remove(channel);
    }

    public void setNews(String news) {
        this.news = news;
        for (Channel channel : this.channels) {
            channel.update(this.news);
        }
    }
}

NewsAgency est une observable, et lorsquenews est mis à jour, l'état deNewsAgency change. Lorsque le changement se produit,NewsAgency avertit les observateurs de ce fait en appelant leur méthodeupdate().

To be able to do that, the observable object needs to keep references to the observers, et dans notre cas, c'est la variablechannels.

Voyons maintenant à quoi peut ressembler l'observateur, la classeChannel. Il doit avoir la méthodeupdate() qui est invoquée lorsque l'état deNewsAgency change:

public class NewsChannel implements Channel {
    private String news;

    @Override
    public void update(Object news) {
        this.setNews((String) news);
    }
}

L'interfaceChannel n'a qu'une seule méthode:

public interface Channel {
    public void update(Object o);
}

Maintenant, si nous ajoutons une instance deNewsChannel à la liste des observateurs, et changeons l'état deNewsAgency, l'instance deNewsChannel sera mise à jour:

NewsAgency observable = new NewsAgency();
NewsChannel observer = new NewsChannel();

observable.addObserver(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");

Il existe une interfaceObserver prédéfinie dans les bibliothèques Java Core, ce qui simplifie encore davantage la mise en œuvre du modèle d'observateur. Regardons ça.

3. Implémentation avecObserver

L'interfacejava.util.Observer définit la méthodeupdate(), il n'est donc pas nécessaire de la définir nous-mêmes comme nous l'avons fait dans la section précédente.

Voyons comment nous pouvons l'utiliser dans notre mise en œuvre:

public class ONewsChannel implements Observer {

    private String news;

    @Override
    public void update(Observable o, Object news) {
        this.setNews((String) news);
    }
}

Ici, le deuxième argument provient deObservable comme nous le verrons ci-dessous.

Pour définir les, observables, nous devons étendre la classeObservable de Java:

public class ONewsAgency extends Observable {
    private String news;

    public void setNews(String news) {
        this.news = news;
        setChanged();
        notifyObservers(news);
    }
}

Notez que nous n'avons pas besoin d'appeler directement la méthodeupdate() de l'observateur. Nous appelons simplementstateChanged() etnotifyObservers(), et la classeObservable fait le reste pour nous.

En outre, il contient une liste d'observateurs et expose des méthodes pour maintenir cette liste -addObserver() etdeleteObserver().

Pour tester le résultat, il suffit d'ajouter l'observateur à cette liste et de définir les nouvelles:

ONewsAgency observable = new ONewsAgency();
ONewsChannel observer = new ONewsChannel();

observable.addObserver(observer);
observable.setNews("news");
assertEquals(observer.getNews(), "news");

L'interface deObserver n'est pas parfaite et est obsolète depuis Java 9. L’un de ses inconvénients est queObservable n’est pas une interface mais une classe, c’est pourquoi les sous-classes ne peuvent pas être utilisées comme observables.

En outre, un développeur peut remplacer certaines des méthodes synchronisées deObservable et perturber la sécurité des threads.

Regardons l’interfaceProperyChangeListener, qui est recommandée au lieu d’utiliserObserver.

4. Implémentation avecPropertyChangeListener

In this implementation, an observable must keep a reference to the PropertyChangeSupport instance. Cela permet d'envoyer les notifications aux observateurs lorsqu'une propriété de la classe est modifiée.

Définissons l'observable:

public class PCLNewsAgency {
    private String news;

    private PropertyChangeSupport support;

    public PCLNewsAgency() {
        support = new PropertyChangeSupport(this);
    }

    public void addPropertyChangeListener(PropertyChangeListener pcl) {
        support.addPropertyChangeListener(pcl);
    }

    public void removePropertyChangeListener(PropertyChangeListener pcl) {
        support.removePropertyChangeListener(pcl);
    }

    public void setNews(String value) {
        support.firePropertyChange("news", this.news, value);
        this.news = value;
    }
}

En utilisant cesupport, nous pouvons ajouter et supprimer des observateurs, et les notifier lorsque l'état de l'observable change:

support.firePropertyChange("news", this.news, value);

Ici, le premier argument est le nom de la propriété observée. Les deuxième et troisième arguments sont donc son ancienne et sa nouvelle valeur.

Les observateurs doivent implémenterPropertyChangeListener:

public class PCLNewsChannel implements PropertyChangeListener {

    private String news;

    public void propertyChange(PropertyChangeEvent evt) {
        this.setNews((String) evt.getNewValue());
    }
}

En raison de la classePropertyChangeSupport qui fait le câblage pour nous, nous pouvons restaurer la nouvelle valeur de propriété à partir de l'événement.

Testons la mise en œuvre pour nous assurer qu'elle fonctionne également:

PCLNewsAgency observable = new PCLNewsAgency();
PCLNewsChannel observer = new PCLNewsChannel();

observable.addPropertyChangeListener(observer);
observable.setNews("news");

assertEquals(observer.getNews(), "news");

5. Conclusion

Dans cet article, nous avons examiné deux façons d'implémenter le modèle de conceptionObserver en Java, l'approchePropertyChangeListener étant préférée.

Le code source de l'article est disponibleover on GitHub.