Article image
Giovanni Rozza
Giovanni Rozza05/05/2023 17:44
Compartilhe

[sw design pattern] Observer (Observador)

    Os padrões de design GoF são classificados em três categorias: Criacionais, Comportamentais e Estruturais. Os padrões criacionais tratam da criação de objetos, enquanto os padrões estruturais lidam com a estrutura das classes, como herança e composição. Por fim, os padrões comportamentais lidam com a comunicação entre objetos e suas interações. Estes padrões de projeto se encontram no livro “Padrões de Projetos: Soluções Reutilizáveis de Software Orientado a Objetos” escrito por 4 autores denominados GoF (Gang of Four).

    O padrão Observer é um padrão de design comportamental que permite que um objeto, chamado de "sujeito", notifique uma lista de objetos dependentes, chamados de "observadores", sobre quaisquer mudanças em seu estado. Isso permite que os observadores sejam atualizados automaticamente sempre que o estado do sujeito muda, sem que o sujeito precise conhecer os detalhes de implementação de cada observador. O padrão Observer é útil em situações em que vários objetos precisam ser notificados sobre mudanças em um objeto central. Por exemplo, em um sistema de estoque, vários objetos, como a interface do usuário, o banco de dados e os relatórios, podem precisar ser atualizados sempre que o estoque de um produto mudar.

    Para implementar o padrão Observer, o sujeito deve manter uma lista de observadores e fornecer métodos para adicionar e remover observadores dessa lista. Quando o estado do sujeito muda, ele deve chamar um método notificar em cada observador na lista, passando informações relevantes sobre a mudança de estado. Os observadores devem implementar uma interface comum que permita ao sujeito notificá-los e atualizá-los sobre as mudanças de estado. Cada observador pode então atualizar seu próprio estado com base nas informações fornecidas pelo sujeito.

    O padrão de design Observer está relacionado a vários outros padrões de design. Aqui estão alguns exemplos:

    1. Padrão Mediator: O padrão Mediator é semelhante ao padrão Observer, pois permite que objetos se comuniquem entre si sem conhecer os detalhes de implementação um do outro. No entanto, no padrão Mediator, há um objeto central (o Mediator) que facilita a comunicação entre os outros objetos, enquanto no padrão Observer, os objetos se comunicam diretamente entre si.
    2. Padrão Decorator: O padrão Decorator é frequentemente usado em conjunto com o padrão Observer para adicionar funcionalidade aos objetos sem alterar sua implementação principal. Por exemplo, você pode usar o padrão Decorator para adicionar logging ou tratamento de erros a um objeto Observer sem modificar seu método update().
    3. Padrão Singleton: O padrão Singleton é às vezes usado em conjunto com o padrão Observer para garantir que haja apenas uma instância do objeto sujeito. Isso pode ser útil em situações em que vários observadores precisam ser notificados sobre mudanças no mesmo objeto sujeito.
    4. Padrão Factory: O padrão Factory pode ser usado para criar instâncias de objetos observadores dinamicamente em tempo de execução. Isso pode ser útil em situações em que o número ou tipo de observadores pode mudar ao longo do tempo.

    Em geral, o padrão Observer é uma ferramenta poderosa para construir sistemas de software flexíveis e extensíveis. Ao permitir que objetos se comuniquem entre si de maneira fracamente acoplada, o padrão Observer promove modularidade, manutenibilidade e escalabilidade.

    Abaixo está um exemplo simples em Java do padrão Observer:

    Suponha que temos um objeto Subject que mantém uma lista de observadores Observer. O Subject tem um método attach() para adicionar um observador à lista, um método detach() para remover um observador da lista e um método notifyObservers() para notificar todos os observadores na lista sobre mudanças no estado do Subject. Cada observador implementa a interface Observer que tem um método update() que é chamado pelo Subject sempre que ocorre uma mudança de estado.

    import java.util.ArrayList;
    import java.util.List;
    
    
    interface Observer {
      void update();
    }
    
    
    class Subject {
      private List<Observer> observers = new ArrayList<>();
      private int state;
    
    
      public int getState() {
          return state;
      }
    
    
      public void setState(int state) {
          this.state = state;
          notifyObservers();
      }
    
    
      public void attach(Observer observer) {
          observers.add(observer);
      }
    
    
      public void detach(Observer observer) {
          observers.remove(observer);
      }
    
    
      public void notifyObservers() {
          for (Observer observer : observers) {
              observer.update();
          }
      }
    }
    
    
    class ConcreteObserver implements Observer {
      private Subject subject;
    
    
      public ConcreteObserver(Subject subject) {
          this.subject = subject;
          subject.attach(this);
      }
    
    
      public void update() {
          System.out.println("State changed to " + subject.getState());
      }
    }
    
    
    public class Main {
      public static void main(String[] args) {
          Subject subject = new Subject();
          ConcreteObserver observer1 = new ConcreteObserver(subject);
          ConcreteObserver observer2 = new ConcreteObserver(subject);
    
    
          subject.setState(1);
          subject.detach(observer2);
          subject.setState(2);
      }
    }
    

    O código acima define uma interface Observer com um método update(), uma classe Subject que mantém uma lista de observadores e notifica todos os observadores na lista sempre que ocorre uma mudança de estado, e uma classe ConcreteObserver que implementa a interface Observer e é notificada pelo Subject sempre que ocorre uma mudança de estado.

    No método main(), criamos um objeto Subject e dois objetos ConcreteObserver. Em seguida, definimos o estado do Subject como 1, o que notifica ambos os observadores. Em seguida, removemos o segundo observador da lista e definimos o estado do Subject como 2, o que notifica apenas o primeiro observador.

    Resumindo, o padrão Observer é usado para notificar vários objetos sobre mudanças em um objeto central. O Subject mantém uma lista de observadores e notifica todos os observadores na lista sempre que ocorre uma mudança de estado. Cada observador implementa a interface Observer e é notificado pelo Subject sempre que ocorre uma mudança de estado. O código acima define as classes Subject, Observer e ConcreteObserver, bem como os métodos attach(), detach(), notifyObservers(), update(), getState() e setState().

    A primeira linha é impressa duas vezes, uma para cada observador adicionado ao Subject. A segunda linha é impressa apenas uma vez, porque um dos observadores foi removido antes que o estado do Subject fosse alterado para 2.

    State changed to 1
    State changed to 1
    State changed to 2
    

    links externos com mais exemplos do padrão Observer:

    —> O código do link abaixo é um exemplo simples do padrão Observer usando a classe PropertyChangeSupport do Java. A classe PCLNewsAgency é o objeto observável que mantém uma propriedade news e notifica seus observadores sempre que essa propriedade é alterada. A classe PCLNewsChannel é um observador que implementa a interface PropertyChangeListener e atualiza sua própria propriedade news sempre que é notificado de uma mudança na propriedade news do objeto observável.

    Resumindo, o padrão Observer é usado para notificar vários objetos sobre mudanças em um objeto central. No código acima, a classe PCLNewsAgency é o objeto observável e a classe PCLNewsChannel é o observador. A classe PCLNewsAgency tem um atributo news e métodos addPropertyChangeListener(), removePropertyChangeListener() e setNews(). A classe PCLNewsChannel tem um atributo news e um método propertyChange(). O código acima também usa os métodos firePropertyChange() e getNewValue() da classe PropertyChangeSupport.

    https://www.baeldung.com/java-observer-pattern

    O código descrito no link abaixo é um exemplo do padrão Observer em Java. Ele define uma classe EventManager que mantém uma lista de ouvintes para diferentes tipos de eventos, uma classe Editor que é o objeto observável que notifica seus ouvintes sempre que um arquivo é aberto ou salvo, e duas classes de ouvintes EmailNotificationListener e LogOpenListener que implementam a interface EventListener e são notificadas pelo Editor sempre que um arquivo é aberto ou salvo.

    Dessa forma, o padrão Observer é usado para notificar vários objetos sobre mudanças em um objeto central. No código acima, a classe EventManager é usada para gerenciar a lista de ouvintes para diferentes tipos de eventos. A classe Editor é o objeto observável que tem um atributo events do tipo EventManager e métodos openFile() e saveFile(). As classes EmailNotificationListener e LogOpenListener são ouvintes que implementam a interface EventListener e têm um método update(). O código acima também usa os métodos subscribe(), unsubscribe() e notify() da classe EventManager. O método main() na classe Demo cria um objeto Editor, adiciona dois ouvintes a ele usando o método subscribe() da classe EventManager, abre um arquivo e salva-o, notificando assim os ouvintes.

    https://refactoring.guru/design-patterns/observer/java/example

    REFERÊNCIAS:

    https://www.amazon.com/Head-First-Design-Patterns-Brain-Friendly/dp/0596007124

    https://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612

    https://refactoring.guru/design-patterns/observer

    https://sourcemaking.com/design_patterns/observer

    https://en.wikipedia.org/wiki/Observer_pattern

    Compartilhe
    Comentários (1)
    IASMIM GODOY
    IASMIM GODOY - 05/05/2023 19:11

    Terei de ler mais vezes, mas é um conteúdo muito significativo para a compreensão a respeito do Padrão de design comportamental Observer e mudanças de estado. Estou seguindo a publicação.