Aprenda a implementar o padrão Observer em Java

Por Gaspar Barancelli Junior em 02 de setembro de 2023

O padrão de projeto Observer é um dos padrões mais utilizados no desenvolvimento de software, especialmente em aplicações com interface gráfica ou que envolvem eventos e atualizações frequentes de dados. Este padrão permite que objetos observadores sejam notificados quando um objeto observado sofre mudanças em seu estado interno, tornando possível a atualização de outros objetos dependentes desse estado.

Quando utilizar o padrão Observer?

O padrão Observer é útil em situações onde é necessário manter um conjunto de objetos sincronizados com o estado de outro objeto. Por exemplo, em um sistema de estoque, podemos ter um objeto "Produto" que armazena informações sobre um produto, como seu nome, preço e quantidade em estoque. Se vários objetos dependem dessas informações, como uma tela de exibição de produtos, um objeto de carrinho de compras e um objeto de histórico de vendas, é importante manter todos esses objetos sincronizados com o estado do objeto "Produto". É aqui que o padrão Observer entra em ação.

Como funciona o padrão Observer?

O padrão Observer é composto por dois tipos de objetos: o sujeito observado e os observadores. O sujeito observado é o objeto que contém o estado interno a ser monitorado, enquanto os observadores são objetos que precisam ser notificados quando esse estado interno é alterado.

O sujeito observado mantém uma lista de observadores registrados e fornece métodos para adicionar e remover observadores dessa lista. Quando o estado interno do sujeito observado muda, ele notifica todos os observadores registrados, que então atualizam seu próprio estado interno de acordo com o novo estado do sujeito.

Exemplo de código em Java:

Vamos considerar um exemplo de implementação do padrão Observer em Java. Suponha que temos um objeto "Produto" que representa um produto em um sistema de estoque, e queremos que vários outros objetos sejam notificados sempre que o estado desse produto mudar. Para isso, vamos criar uma classe "Produto" que implementa o sujeito observado, e uma classe "TelaDeExibicaoDeProduto" que implementa um observador.

Interface ObservadorDeProduto:

public interface ObservadorDeProduto {
    void atualizar(Produto produto);
}

A interface ObservadorDeProduto possui apenas um método, "atualizar()", que é chamado pelo sujeito observado quando o estado interno do objeto mudar. Como parâmetro, este método recebe o objeto "Produto" atualizado, permitindo que o observador obtenha as informações necessárias para atualizar seu próprio estado interno. Os observadores concretos implementam esta interface e fornecem uma implementação específica para o método "atualizar()".

Classe Produto:

import java.util.ArrayList;
import java.util.List;

public class Produto {
    private String nome;
    private double preco;
    private int quantidade;
    private List<ObservadorDeProduto> observadores = new ArrayList<>();

    public Produto(String nome, double preco, int quantidade) {
        this.nome = nome;
        this.preco = preco;
        this.quantidade = quantidade;
    }

    public void adicionarObservador(ObservadorDeProduto obs) {
        observadores.add(obs);
    }

    public void removerObservador(ObservadorDeProduto obs) {
        observadores.remove(obs);
    }

    public void notificarObservadores() {
        for (ObservadorDeProduto obs : observadores) {
            obs.atualizar(this);
        }
    }

    public void setPreco(double novoPreco) {
        this.preco = novoPreco;
        notificarObservadores();
    }

    public void setQuantidade(int novaQuantidade) {
        this.quantidade = novaQuantidade;
        notificarObservadores();
    }
}

A classe "Produto" é o sujeito observado, que mantém uma lista de observadores (objetos que implementam a interface "ObservadorDeProduto"). Quando o preço ou a quantidade do produto são atualizados, a classe "Produto" chama o método "notificarObservadores()", que por sua vez chama o método "atualizar()" de cada observador registrado na lista.

Classe TelaDeExibicaoDeProduto:

public class TelaDeExibicaoDeProduto implements ObservadorDeProduto {
    private Produto produto;

    public TelaDeExibicaoDeProduto(Produto produto) {
        this.produto = produto;
        produto.adicionarObservador(this);
    }

    @Override
    public void atualizar(Produto produto) {
        System.out.println("Atualizando tela de exibição do produto: " + produto.getNome() + " - Preço: " + produto.getPreco() + " - Quantidade em estoque: " + produto.getQuantidade());
    }
}

A classe "TelaDeExibicaoDeProduto" é um exemplo de observador, que implementa a interface "ObservadorDeProduto". Quando um objeto "TelaDeExibicaoDeProduto" é criado, ele se registra como observador do objeto "Produto" passado como parâmetro no construtor. Quando o método "atualizar()" é chamado, a tela de exibição do produto é atualizada com as informações mais recentes do objeto "Produto".

Conclusão

O padrão Observer é uma ferramenta poderosa para manter objetos dependentes sincronizados com o estado interno de outros objetos em uma aplicação. Quando usado corretamente, o padrão Observer pode ajudar a melhorar a modularidade e a escalabilidade do código, tornando-o mais fácil de entender, modificar e manter. O exemplo de código Java apresentado aqui é apenas um dos muitos casos de uso possíveis para este padrão, e é importante lembrar que a escolha de padrões de projeto deve ser baseada nas necessidades específicas de cada projeto.

// Compartilhe esse Post

💫
🔥 NOVO APP

Domine o Inglês em 30 dias!

Inteligência Artificial + Repetição Espaçada • Método cientificamente comprovado

✅ Grátis para começar 🚀 Resultados rápidos
×