JavaRush /Blogue Java /Random-PT /Modelo de observador

Modelo de observador

Publicado no grupo Random-PT
Como escreve o Gang of Four (referindo-se ao livro “Object-Oriented Design Patterns” de 4 desenvolvedores de primeira linha), o objetivo deste padrão é definir uma dependência um-para-muitos entre objetos de tal forma que quando o O estado de um objeto muda, todos aqueles que dependem dele são notificados sobre isso e atualizados automaticamente. Este padrão também é chamado de: Dependentes (subordinados) ou Publish-Subscribe (editor - assinante). Mas vamos tentar descobrir usando o exemplo da Igreja Católica :) Ela tem seguidores que acreditam nos ensinamentos desta igreja. Quando quaisquer novos dogmas (credos obrigatórios) e mais aparecerem, essas pessoas deverão saber sobre eles. Mas como isso poderia ser descrito em uma linguagem de programação usando esse padrão? 1. Temos a “voz da igreja” (a própria igreja ou o Papa quando transmite ex cathedra), ou seja, um determinado locutor ou sujeito que anuncia notícias na igreja. 2. Existem paroquianos desta igreja, ou seja, alguns observadores que querem estar a par de acontecimentos importantes. Assim, hoje pode haver 1,3 mil milhões de paroquianos e amanhã pode haver mais ou menos. E você só precisa avisar quem está nesta igreja (não há necessidade de incomodar os ateus de novo :). Assim, tudo isso poderia ser expresso da seguinte forma: Existe uma igreja que vai contar algo ao seu rebanho, na qual você pode se inscrever ou, pelo contrário, deixá-la:
public interface Church {
    void registerParishioner(Parishioner parishioner);
    void removeParishioner(Parishioner parishioner);
    void notifyParishioners();
}
Existe uma Igreja Católica específica com a implementação destes métodos, bem como notícias e uma lista de pessoas a quem esta notícia deve ser transmitida:
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);
    }
}
Há um paroquiano que pode entrar ou sair da igreja (para simplificar o código, só permitiremos a sua entrada :)
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);
    }
}
Assim, é assim que funcionará:
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 года");
    }
}
e o resultado do programa:
Мартин Лютер узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Жан Кальвин узнал новость: Инквизиция была ошибкой... месса Mea Culpa 12 марта 2000 года
Aqueles. assim que surgirem notícias na igreja, todos que estiverem no quadro de membros cadastrados desta igreja serão avisados. Quais são as desvantagens desta implementação: 1. Em primeiro lugar, a interface onde você pode se registrar e receber notícias pode não dizer respeito apenas a esta igreja (isso pode ser necessário). Portanto, seria possível mover isso imediatamente para uma interface Observable separada. 2. O mesmo poderia ser feito com os paroquianos da igreja, nomeadamente, mover o método de atualização para uma interface separada e implementá-lo para o paroquiano pretendido. Então este método poderá ser utilizado em geral não pelos paroquianos da Igreja Católica, mas, por exemplo, por aqueles que vivem na existência de elfos (ou seja, o movimento “Caminho para o Unicórnio”). Aqueles. crie uma interface Observer com um método de atualização. O que vai acontecer no final:
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);
    }
}
Assim: “Enfraquecemos a ligação” entre a igreja e os paroquianos, o que naturalmente só é bom na programação :) A disciplina (Igreja Católica) tem apenas uma lista de ouvintes (paroquianos) e ao receber notícias (mudanças), transmite esta notícia aos seus ouvintes. Agora você pode criar qualquer outra entidade (por exemplo, uma igreja protestante) e transmitir a notícia para “seus” ouvintes. Você também precisa levar em consideração que os dados da classe 2 (mais precisamente, a classe Observable e a interface Observer) estavam disponíveis no pacote java.util java, mas agora estão Deprecation com java 9 (https://docs.oracle. com/en/java/javase/15/docs/api/java.base/java/util/Observable.html): obsoleto. Esta classe e a interface Observer foram descontinuadas. O modelo de evento suportado por Observer e Observable é bastante limitado, a ordem das notificações entregues por Observable não é especificada e as mudanças de estado não correspondem às notificações um por um. Para um modelo de evento mais rico, considere usar o pacote java.beans. Para mensagens confiáveis ​​e ordenadas entre encadeamentos, considere usar uma das estruturas de dados simultâneas no pacote java.util.concurrent. Para programação no estilo de fluxos reativos, consulte a API Flow. Portanto não há necessidade de utilizá-los. E você pode usar outros, mas a essência do padrão não mudará. Por exemplo, vamos tentar usar PropertyChangeListener (para não escrever classes desnecessárias que já foram escritas) do pacote java.beans. Vamos ver como vai ser: aula de assunto:
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;
    }
}
e a classe ouvinte:
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);
    }
}
Se executarmos o seguinte código:
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 год");
}
Obtemos o seguinte resultado:
Martinho Lutero recebeu a notícia: A Virgem Maria é da Imaculada Conceição... bula Ineffabilis Deus... 8 de dezembro de 1854 O Papa Pio IX João Calvino recebeu a notícia: A Virgem Maria é da Imaculada Conceição... Bula Ineffabilis Deus ... 8 de dezembro de 1854 Papa Pio IX Martinho Lutero soube da notícia: O Papa é infalível... nem sempre, é claro, mas apenas quando ele transmite os ensinamentos da igreja ex cathedra... Primeiro Concílio Vaticano de 1869, João Calvino aprendeu a notícia: O Papa é infalível... nem sempre, claro, mas apenas quando ele transmite o ensinamento da Igreja ex cathedra... Primeiro Concílio Vaticano 1869
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION