Desenvolvimento - Java

Padrões em Java: Observer

Nesse artigo iremos conhecer um pouco mais sobre o Padrão Java Observer, um padrão de projetos em Java.

por Diogo Souza



1. Introdução

Segundo a Wikipedia o padrão Observer é:

“Um padrão de projeto de software em que um objeto, chamado “subject”, mantém uma lista de seus dependentes, chamados de “observers”, e os notifica automaticamente de eventuais mudanças de estado, geralmente, chamando um dos seus métodos. É usado principalmente para implementar sistemas de tratamento de eventos distribuídos. O padrão Observer é também uma peça-chave no familiar padrão de arquitetura Model View Controller (MVC). Na verdade, o padrão Observer foi implementado pela primeira vez no framework MVC de interface de usuário Smalltalk. O observador padrão é implementado em inúmeras bibliotecas de programação e sistemas, incluindo quase todas as ferramentas GUI.”

Basicamente, é um padrão de projetos que define uma espécie de audição aos eventos selecionados para serem observados. Tal como descrito na Wikipédia, na grande maioria dos frameworks e bibliotecas de interfaces gráfica, em Java por exemplo, temos a presença constante de ouvintes de eventos que capturam determinados eventos de usuário (cliques, focos, teclas pressionadas, etc.) e executam ações respectivas a cada um dos mesmos.

O modelo do padrão define a criação de dois atores principais: o objeto sendo observado (o subject, ou observable) e o objeto observador (observer , ou listener), ambos com interfaces respectivas para registrar os métodos obrigatórios. E define para o mesmo, um tipo de relacionamento de dependência de one-to-many (um-para-muitos) entre os mesmos objetos, para que, em um dado momento que o estado do objeto for alterado, todos os objetos dependentes recebam essa atualização via pattern.

Esse padrão é bem comum no universo de desenvolvimento Java. Suponha, por exemplo, que você tenha um sistema que gerencia o seu regime. Com o passar dos dias você usará o sistema e informará diariamente o seu peso e as alterações do mesmo. Você terá uma classe A que receberá essa informação e que irá atrelar à ela mesma uma classe B (O observer), para notificar toda alteração que aconteça. Quando a mesma ultrapassar um limite definido pelo IMC de massa corpórea o observer será avisado e então tomará as medidas cabíveis. Este é apenas um de muitos exemplos possíveis para o padrão, e, independente do caso, o modelo representado na Figura 1 pode explanar melhor como suas classes poderão se dividir.

Representação de classes do padrão Observer

Figura 1 - Representação de classes do padrão Observer

2. Implementação em Java

Interface pública Observer: As classes que implementarem essa interface, que por sua vez conterá um método de atualização (update), deverão ser notificadas quando da atualização ou mudança do estado do objeto observado.

Classe Observable: Define a classe que será observada. Essa classe geralmente guarda como atributo uma lista (Lista Java comum, Collections) dos observers associados à mesma, para que os mesmos possam ser notificados quando a mudança acontecer na classe.

Alguns métodos geralmente usados:

  • registerObserver(Observer observer): Adiciona o observer passado por parâmetro à lista de observadores do objeto observado;
  • deleteObserver(Observer observer): Remove o observer passado por parâmetro da lista de observadores do objeto observado;
  • hasChanged(): Verifica se o objeto sofreu alguma mudança;
  • notifyObservers(): Notifica todos os observers caso haja alguma mudança no objeto observado.

Basicamente as duas interfaces acima descritas ficariam tais como definidas nas Listagens 1 e 2.

Listagem 1. Implementação da interface Java Observer

public interface Observer {
    public void update(Object obj);
}

Listagem 2. Implementação da interface Java Observable

public interface Observable {
    public void registerObserver(Observer observer);
    public void removeObserver(Observer observer);
    public void notifyObservers();	
}

Na Listagem 1 é possível observar a criação do método update(Object obj) que é usado para conter a regra de atualização específica de cada observador. Logo, a interface define um contrato de implementação obrigatório para com os objetos observadores, de que eles terão de tomar alguma providência, executar alguma ação, após as notificações de mudança no objeto observado.

Dentro da api do Java JSE é possível encontrar também duas classes que já implementam o padrão: a java.util.Observer e a java.util.Observable. Ambas contêm os métodos aqui descritos bem como a possibilidade de se adaptarem às diferentes realidades de casos de usos nos sistemas, porém, é interessante se implementar as próprias interfaces em detrimento de um controle maior sobre o código gerado, bem como possíveis futuras alterações possíveis de acontecer.

Levando em consideração o exemplo explanado no início do artigo, veja na Listagens 3 e 4 como ficaria o código do mesmo para as classes que implementam as interfaces em questão.

Listagem 3. Classe observada Dieta.java

public class Dieta implements Observable {
       private List observers = new ArrayList();
       private double peso;

       public Dieta(double peso) {
            this.peso = peso;
       }

public void setPeso(double peso) {
		this.peso = peso;
		// Quando a alteração do peso ocorrer, esse é o momento correto para notificar os observers.
		this.notifyObservers();
	}

       @Override
       public void registerObserver(Observer observer) {
            observers.add(observer);
       }

       @Override
       public void removeObserver(Observer observer) {
            observers.remove(observer);
       }

       @Override
       public void notifyObservers() {
		// Chama o método de atualização de todos os observers disponíveis.
       		for (Observer ob : observers) {
			System.out.println("Notificando observers!");
              ob.update(this.peso);
       		}
       }
}

Listagem 4. Classe observadora BalancaDieta.java

// Classe observadora "Balança"
class BalancaDieta implements Observer {
       @Override
       public void update(double novoPeso) {
		if (peso >= 100) {
			System.out.println("Você ultrapassou o peso limite no sistema!");
		}
       }
}

As duas classes representadas acima ilustram, de forma comentada, o processo necessário para ouvir os eventos de mudança no peso da dieta e notificar os respectivos observers que irão validar tal mudança.

Na Listagem 5 é possível observar o método de chamada, teste, do exemplo acima.

Listagem 5. Classe de teste do Observer criado

public class Teste {
	public static void main(String args[]) {
		BalancaDieta balanca = new BalancaDieta();
		Dieta dieta = new Dieta();
		personalLoan.registerObserver(balanca);
		dieta.setPeso(150);
	}
}

Atente para a ordem das setagens e criação de objetos no exemplo da Listagem 5. É importante que antes que o objeto sofra de qualquer alteração, ele esteja com seus observers devidamente regristrados.

3. Concluindo

Usar padrões de projeto se torna cada vez mais necessário em vista das inúmeras e novas funcionalidades exigidas pelos clientes, assim como a rapidez de implementação exigida pelos mesmos. Para tanto, é necessário também que o desenvolvedor tenha um bom nível de intimidade com o padrão, para que possa usá-lo da forma correta, ou pelo menos identificar quando o mesmo se encaixa.

O padrão Observer, conforme falado anteriormente, é amplamente usado pela comunidade, tanto que já se encontra dentro da própria api da linguagem. Portanto, não deixe que tal recurso poderoso se perca em meio à falta de conhecimento ou preconceito em relação aos padrões de projetos. Use-o.

Navegando pela web, encontrei um material muito interessante para quem quer aprender Java, trata-se do Checklist Programador Javada DevMedia. Recomendo a todos que querem se aprofundar na linguagem e se tornarem um programador Java de sucesso.

Diogo Souza

Diogo Souza - Diogo Souza trabalha como Analista de Sistemas Java na Indra Company e já trabalhou em empresas como Instituto Atlântico e Ebix L.A, até fundar a própria empresa 3adiX Tech, da qual é sócio, instrutor e desenvolvedor. É instrutor Android, palestrante em eventos sobre Java e o mundo mobile e consultor DevMedia.