JavaRush /Blog Java /Random-FR /Modèle d'observateur

Modèle d'observateur

Publié dans le groupe Random-FR
Comme l'écrit le Gang of Four (en faisant référence au livre « Object-Oriented Design Patterns » de 4 développeurs de premier ordre), le but de ce modèle est de définir une dépendance un-à-plusieurs entre les objets de telle manière que lorsque le l'état d'un objet change, tous ceux qui en dépendent en sont informés et sont automatiquement mis à jour. Ce modèle est également appelé : Personnes à charge (subordonnés) ou Publier-Abonnez-vous (éditeur - abonné). Mais essayons de le comprendre en utilisant l'exemple de l'Église catholique :) Elle a des adeptes qui croient aux enseignements de cette église. Lorsque de nouveaux dogmes (croyances obligatoires) et autres apparaissent, ces gens devraient en être informés. Mais comment cela pourrait-il être décrit dans un langage de programmation utilisant ce modèle ? 1. Nous avons la « voix de l’Église » (l’Église elle-même ou le Pape lors de la diffusion ex cathedra), c’est-à-dire un certain diffuseur ou sujet qui annonce des nouvelles dans l’Église. 2. Il y a des paroissiens de cette église, c'est-à-dire des observateurs qui veulent être au courant des événements importants. Ainsi, aujourd'hui, il pourrait y avoir 1,3 milliard de paroissiens, et demain il y en aura peut-être plus ou moins. Et il vous suffit d'avertir ceux qui sont dans cette église (plus besoin de déranger les athées :). Ainsi, tout cela pourrait s'exprimer ainsi : Il y a une église qui racontera quelque chose à ses fidèles, dans laquelle vous pourrez vous inscrire ou, au contraire, la quitter :
public interface Church {
    void registerParishioner(Parishioner parishioner);
    void removeParishioner(Parishioner parishioner);
    void notifyParishioners();
}
Il existe une Église catholique spécifique avec la mise en œuvre de ces méthodes, ainsi que des informations et une liste de personnes à qui ces informations doivent être diffusées :
public class CatholicChurch implements Church {
    private List<parishioner> parishioners;
    private String newsChurch;

    public CatholicChurch() {
        parishioners = new ArrayList<>();
    }

    public void setNewsChurch(String news) {
        this.newsChurch = news;
        notifyParishioners();
    }

    @Override
    public void registerParishioner(Parishioner parishioner) {
        parishioners.add(parishioner);
    }

    @Override
    public void removeParishioner(Parishioner parishioner) {
        parishioners.remove(parishioner);
    }

    @Override
    public void notifyParishioners() {
        for (Parishioner parishioner : parishioners)
            parishioner.update(newsChurch);
    }
}
Il y a un paroissien qui peut entrer ou sortir de l'église (pour simplifier le code, nous lui laisserons seulement entrer :)
public class Parishioner {

    private String name;

    public Parishioner(String name, Church church) {
        this.name = name;
        church.registerParishioner(this);
    }

    void update(String newsChurch) {
        System.out.println(name + "узнал новость: " + newsChurch);
    }
}
En conséquence, voici comment cela fonctionnera :
public class Main {
    public static void main(String[] args) {
        var catholicChurch = new CatholicChurch();

        new Parishioner("Мартин Лютер", catholicChurch);
        new Parishioner("Жан Кальвин", catholicChurch);

        catholicChurch.setNewsChurch("Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года");
    }
}
et le résultat du programme :
Мартин Лютер узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Жан Кальвин узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Ceux. Dès que des nouvelles apparaîtront dans l'église, tous ceux qui font partie du groupe des membres enregistrés de cette église en seront informés. Quels sont les inconvénients de cette implémentation : 1. Premièrement, l'interface où vous pouvez vous inscrire et recevoir des nouvelles peut concerner non seulement cette église (cela peut être obligatoire). Par conséquent, il serait possible de déplacer immédiatement cela dans une interface Observable distincte. 2. La même chose pourrait être faite avec les paroissiens d'église, à savoir déplacer la méthode de mise à jour dans une interface distincte et la mettre en œuvre pour le paroissien souhaité. Cette méthode pourra alors être utilisée en général non pas par les paroissiens de l'Église catholique, mais, par exemple, par ceux qui vivent dans l'existence des elfes (c'est-à-dire le mouvement « La Route de la Licorne »). Ceux. créer une interface Observer avec une méthode de mise à jour. Que se passera-t-il à la fin :
interface Observable {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}
public class CatholicChurch implements Observable {
    private List<observer> parishioners;
    private String newsChurch;

    public CatholicChurch() {
        parishioners = new ArrayList<>();
    }

    public void setNewsChurch(String news) {
        this.newsChurch = news;
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer o) {
        parishioners.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        parishioners.remove(o);
    }

    @Override
    public void notifyObservers() {
        for (Observer o : parishioners)
            o.update(newsChurch);
    }
}
interface Observer {
    void update (String news);
}
public class Parishioner implements Observer {
    private String name;

    public Parishioner(String name, Observable o) {
        this.name = name;
        o.registerObserver(this);
    }

    @Override
    public void update(String news) {
        System.out.println(name + " узнал новость: " + news);
    }
}
Ainsi : Nous avons « affaibli le lien » entre l'église et les paroissiens, ce qui n'est naturellement bon qu'en programmation :) Le sujet (église catholique) n'a qu'une liste d'auditeurs (paroissiens) et lorsqu'il reçoit des nouvelles (changements), diffuse ces nouvelles à ses auditeurs. Vous pouvez désormais créer n’importe quelle autre entité (par exemple, une église protestante) et diffuser l’information à « vos » auditeurs. Vous devez également prendre en compte que les données de classe 2 (plus précisément, la classe Observable et l'interface Observer) étaient disponibles dans le package java java.util, mais elles sont désormais obsolètes avec java 9 (https://docs.oracle. com/en/java/javase/15/docs/api/java.base/java/util/Observable.html) : obsolète. Cette classe et l'interface Observer sont obsolètes. Le modèle d'événement pris en charge par Observer et Observable est assez limité, l'ordre des notifications délivrées par Observable n'est pas spécifié et les changements d'état ne correspondent pas un pour un aux notifications. Pour un modèle d'événement plus riche, envisagez d'utiliser le package java.beans. Pour une messagerie fiable et ordonnée entre les threads, envisagez d'utiliser l'une des structures de données simultanées du package java.util.concurrent. Pour la programmation de style flux réactifs, consultez l'API Flow. Il n’est donc pas nécessaire de les utiliser. Et vous pouvez en utiliser d'autres à la place, mais l'essence du modèle ne changera pas. Par exemple, essayons d'utiliser PropertyChangeListener (afin de ne pas écrire de classes inutiles déjà écrites) à partir du package java.beans. Voyons comment cela se passera : sujet classe :
public class CatholicChurch {
    private String news;
    // используя support мы можем добавлять or удалять наших прихожан (слушателей)
    private PropertyChangeSupport support;

    public CatholicChurch() {
        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;
    }
}
et la classe d'écoute :
public class Parishioner implements PropertyChangeListener {
    private String name;

    public Parishioner(String name) {
        this.name = name;
    }

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

    public void setNews(String news) {
        System.out.println(name + " узнал новость: " + news);
    }
}
Si on exécute le code suivant :
public static void main(String[] args) {
    CatholicChurch observable = new CatholicChurch();

    observable.addPropertyChangeListener(new Parishioner("Мартин Лютер"));
    observable.addPropertyChangeListener(new Parishioner("Жан Кальвин"));

    observable.setNews("Дева Мария имеет непорочное зачатие... булла Ineffabilis Deus... 8 декабря 1854 года Папа Пий IX");
    observable.setNews("Папа непогрешим... не всегда конечно, а только когда транслирует учение церкви ex cathedra... Первый Ватиканский собор 1869 год");
}
On obtient le résultat suivant :
Martin Luther apprend la nouvelle : La Vierge Marie est de l'Immaculée Conception... bulle Ineffabilis Deus... 8 décembre 1854 Le pape Pie IX Jean Calvin apprend la nouvelle : La Vierge Marie est de l'Immaculée Conception... Bulle Ineffabilis Deus ... 8 décembre 1854 Le Pape Pie IX Martin Luther apprend la nouvelle : Le Pape est infaillible... pas toujours bien sûr, mais seulement lorsqu'il diffuse ex cathedra les enseignements de l'Église... Premier Concile Vatican 1869 Jean Calvin l'apprend la nouvelle : Le Pape est infaillible... pas toujours bien sûr, mais seulement lorsqu'il diffuse ex cathedra l'enseignement de l'Église... Concile Vatican I 1869
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION