Design Patterns Java - Observer

/ Nenhum comentário
Para a explicação desse padrão de projeto vamos supor que estamos em uma cidade e somos clientes de uma banco X. Assim como diversos outros clientes do banco, queremos ser avisados de quando o mesmo abrir para que possamos pagar nossas contas. Este é um bom exemplo para que possamos entender o funcionamento do padrão de projeto Observer: temos um ou mais objetos (os clientes) interessados em saber quando outro objeto (o banco) sofrer alguma mudança de estado.

De acordo com a Wikipédia o Observer é um padrão de projeto de software que define uma dependência um-para-muitos entre objetos de modo que quando um objeto muda o estado, todos seus dependentes são notificados e atualizados automaticamente. Permite que objetos interessados sejam avisados da mudança de estado ou outros eventos ocorrendo num outro objeto.

A classe Cliente

Para começarmos, iremos criar a nossa classe Cliente. Será uma classe bem básica, possuindo apenas o atributo nome, o construtor e um método getNome():

public class Cliente {

    private String nome;

    public Cliente(String nome) {
        this.nome = nome;
    }

    public String getNome() {
        return nome;
    }

} 

A classe Banco

Com a classe dos clientes feita, vamos agora fazer o nosso Banco. O banco também será bem simples, ele possui os atributos nome e aberto, além dos métodos getNome(), abrir() e isAberto().

public class Banco {

    private String nome;
    private boolean aberto;

    public Banco(String nome) {
        this.aberto = false;
        this.nome = nome;
    }

    public String getNome() {
        return nome;
    }

    public void abrir() {
        this.aberto = true;
    }

    public boolean isAberto() {
        return aberto;
    }

}

Nosso método abrir() como o nome já diz, é responsável por abrir o nosso banco, alterando o valor de aberto para true.

Pronto, a nossa base está pronta, agora precisamos encontrar uma forma de fazer com que o nosso banco avise ao cliente que ele está aberto. E é ai que entra o padrão Observer.

A interface Observer

Vamos criar um interface (eu dei o nome de BancoObserver) que será responsável por definir o método de notificação em nossa classe Cliente:

public interface BancoObserver {

    void notifica(Banco banco);

}

Implementando a interface no nosso cliente

Os nossos observadores serão os clientes, então, a classe responsável por implementar a nossa interface BancoObserver é a classe Cliente. Basta inserir implements BancoObserver após o public class Cliente, em seguida o Eclipse ou qualquer outra IDE que você esteja usando pede para que seja implementado o método de nossa interface, implemente-o. No método implementado você pode usar um System.out.println() para mostrar alguma coisa na tela:

@Override
public void notifica(Banco banco) {
    System.out.println("Notificando " + this.nome + " de que o banco " + banco.getNome() + " esta aberto!");
}

Modificando o nosso Banco

A nossa classe Cliente está pronta, mas o nosso banco precisa ser modificado para que ele possa notificar os clientes, então para isto precisamos:
  1. Criar uma lista que armazenará todos os clientes interessados.
  2. Criar um método responsável por registrar os clientes interessados.
  3. Fazer uma modificação em nosso método abrir().

A nossa lista (de observadores) será um ArrayList do tipo BancoObserver que será instanciado no construtor:

// Outros atributos...

private List<BancoObserver> observers;

public Banco(String nome) {
    this.observers = new ArrayList<>();
    this.aberto = false;
    this.nome = nome;
}

// Outros métodos...


Agora, o nosso método de registro de clientes interessados responsável por adicionar um observador na lista precisará receber um BancoObserver como atributo, ele será bem simples:

public void registraObserver(BancoObserver observer) {
    this.observers.add(observer);
}

E por último o nosso método abrir() que está intimamente ligado com o nosso atributo aberto será responsável por avisar aos nossos observadores que o banco abriu. Para isto, vamos criar um for each que percorrerá toda a nossa lista chamando o método de notificação de nossos clientes (os observadores).

public void abrir() {
    this.aberto = true;
    for (BancoObserver observer: observers) {
        observer.notifica(this);
    }
}

Você pode criar um novo método responsável apenas para fazer este for each para modularizar ainda mais o seu programa.

Testando o programa

Com tudo isso feito, está na hora de testarmos nosso programa e ver se está funcionando tudo como o esperado:

public class TestaObserver {

    public static void main(String[] args) {

        Banco bancoDaCidade = new Banco("Banco da Cidade");

        Cliente joao = new Cliente("Joao Gabriel");
        Cliente maria = new Cliente("Maria Vieira");
        Cliente pedro = new Cliente("Pedro Jose");

        bancoDaCidade.registraObserver(joao);
        bancoDaCidade.registraObserver(pedro);

        bancoDaCidade.abrir();

    }

}

A nossa classe de teste é como se fosse a nossa cidade. Nela temos o banco chamado de Banco da Cidade (linha 5) e seus clientes: João, Maria e Pedro (linhas 7 a 9). João e Pedro querem saber quando o banco irá abrir para eles poderem pagar sua contas (linhas 11 e 12), já Maria, ela usa o celular para realizar os pagamentos e não que ser informada da abertura do banco.

Quando o método bancoDaCidade.abrir() for executado todos os clientes registrados serão automaticamente avisados.

Notificando Joao Gabriel de que o banco Banco da Cidade esta aberto!
Notificando Pedro Jose de que o banco Banco da Cidade esta aberto!

Código completo das classes