Saltar para o conteúdo

Observer

Origem: Wikipédia, a enciclopédia livre.

O padrão Observer (tambem conhecido como Dependents, Publish-Subscribe) é um padrão de projeto de software (do inglês design pattern), considerado um padrao comportamental, define um dependencia um-para-muitos, onde permite que a modificação do estado de um objeto, notifique seus dependentes, sendo atualizados automaticamente.

Aplicação

Pode ser utilizado quando existe uma abstração de dois aspectos, sendo um dependente do outro, ou também quando um objeto sofre uma mudança obriga mudança em outros objetos, sem saber quantos objetos precisam mudar, ou quando pode ser capaz de notificar outros objetos, sem que os objetos sejam fortemente acoplados.

Estrutura

Estrutura básica do padrão Observer

[1]

Participantes

Subject (Sujeito)

  • fornece uma interface para acrescentar e remover objetos.

Observer (Observador)

  • fornece uma interface com um metodo chamado update() que permite a atualização de todos os objetos dependentes, quando existe mudança no estado de Subject.

ConcreteSubject (Sujeito concreto)

  • implementa os métodos da interface Subject, e ainda o um outro método notifyObservers(), utilizado para a atualização dos observadores sempre que o estado for alterado. Alem de poder possuir métodos que permitam definir seu estado.

ConcreteObserver (Observador concreto)

  • armazena estados que devem permanecer consistentes com os do Subject, podendo ser qualquer classe que implemente a interface Observer, para manter seu estado consistente com o do subject.

Interação

O ConcreteSubject notifica seus observadores sempre que ocorrer uma mudança, permitindo assim ter uma consistencia dos estados entre ele e seus observadores. Posteriormente ao ser informado, um objeto ConcreteObserver poderá consultar as informações do subject, conciliando suas informações. Pode haver inumeras interfaces do usuário para os mesmos dados, onde o padrão observer permite estabelecer tais relacionamentos. Um subject pode ter diversos observadores dependentes, onde todos são notificados quando o subject sofre uma mudança de estado, sendo apenas o publicador de notificações, enviando essas notificações sem precisar saber quem são os observadores.

Consequências

O padrão Observer permite sujeitos e observadores de foma independente.

Vantagens e Desvantagens

  • Assim Tanto observadores quando sujeitos observados podem ser reutilizados e ter sua interface e implementação alteradas sem afetar o sistema.
  • Acoplamento forte reduzido com o uso de interfaces e classes abstratas

Permite tembem acrescentar observadores sem modificar o sujeito ou outros observadores, assim como outros beneficios e dificuldades:

  • Acoplamento abstrato entre Subject e Observer - O sujeito não conhece a classe concreta de nenhum observador, permitindo que o acoplamento entre o sujeito e os observadores é abstrato e mínimo;
  • Suporte para comunicações do tipo broadcast - a notificação é transmitida automaticamente para todos os objetos interessados, sendo que o sujeito não se preocupa com quantos objetos interessados existem;
  • Atualizações inesperadas - Critérios de depêndencia que não estão bem-definidos ou mantidos normalmente conduzem a atualização normais que podem ser difíceis de detectar;

Implementação

A seguir demonstra um código fonte em Java, onde representamos uma sala de aula, que possui como sujeito concreto a classe Sinal e Professora, que implementa a inteface Sujeito, e seus observadores temos a classe Aluno e Estagiaria, que implementa a inteface Observer.

Subject

Classe Sujeito

Especifica todos as ações comuns aos sujeitos concretos, que podem adicionar os observadores, remove-los e notifica-los.

// <<interface>> Subject

package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado

// fornece a interface que sera utilizada pelos ConcreteSubject(Professora, Sirene)
public interface Sujeito {

    public void addObservador(Observador o);
    public void removeObservador(Observador o);
    public void notificaObservadores();
}

Observer

Classe Observador

Especifica todos as ações comuns aos obsevadores concretos, que podem ser atualizados.

// <<interface>> Observer

package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado

// fornece a interface que será utilizada pelo ConcreteObserver(Aluno, Estagiaria)
public interface Observador {
    public void Update(Sujeito s);
}

ConcreteSubject

Classe Professora

Implementa todas as funções do Subject adicionando e removendo observadores, alem de poder possuir métodos que permitam definir seu estado. Assim ele possui dois observadores que é os observadores concretos Aluno e Estagiaria.

//ConcreteSubject2

package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado

import java.util.ArrayList;

public class Professora implements Sujeito{

     private ArrayList<Observador> observadores;
     private String comando;
     
     public Professora(){
         this.observadores = new ArrayList<Observador>();
     }
     
    public void addObservador(Observador o) { // adiciona o observador
        this.observadores.add(o);
    }

    public void removeObservador(Observador o) { // remove o observador
        this.observadores.remove(o);
    }

    public void notificaObservadores() {  // notifica os observadores
        for(int i = 0; i<this.observadores.size(); i++)
            this.observadores.get(i).Update(this);
    }

    public String getComando() {
        return comando;
    }

    public void setComando(String comando) {
        this.comando = comando;
        this.notificaObservadores();
    }
}

Classe Sirene

Implementa todas as funções do Subject adicionando e removendo observadores, alem de poder possuir métodos que permitam definir seu estado. Assim como o sujeito concreto Professora ele possui dois observadores que é os observadores concretos Aluno e Estagiaria.

//ConcreteSubject1

package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado

import java.util.ArrayList;


public class Sirene implements Sujeito{
    private boolean alertaSonoro;
    
    private ArrayList<Observador> observadores;
    
    public Sirene(){
        this.observadores = new ArrayList();
    }

    public void addObservador(Observador o) { // adiciona o observador
        this.observadores.add(o);
    }

    public void removeObservador(Observador o) { // remove o observador
        this.observadores.remove(o);
    }

    

    public boolean isAlertaSonoro() {
        return alertaSonoro;
    }

    public void setAlertaSonoro(boolean alertaSonoro) {
        this.alertaSonoro = alertaSonoro;
        this.notificaObservadores();
    }
    
    public void notificaObservadores() { // notifica os observadores
        
        for(int i=0; i<this.observadores.size(); i++)
            this.observadores.get(i).Update(this);
    }
}

ConcreteObserver

Classe Aluno

Implementa todas as funções do Observador que armazena estados que devem permanecer consistentes com os do sujeito concreto para manter seu estado consistente com o do subject.

// ConcreteObserver1

package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado

public class Aluno implements Observador{

    public Aluno(){} //Construtor padrão

    public void Update(Sujeito s) {
       
        if(s instanceof Sirene)
            System.out.println(" Aluno - Hora de entregar a prova!");
        else 
            if(s instanceof Professora)
            System.out.println(" Aluno - A professora disse: " + ((Professora) s).getComando());
    }
}

Classe Estagiaria

Assim como a classe Aluno, essa classe implementa todas as funções do Observador que armazena estados que devem permanecer consistentes com os do sujeito concreto para manter seu estado consistente com o do subject.

//ConcreteObserver2

package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado


public class Estagiaria implements Observador {
    
    public Estagiaria(){} // construtor padrão vazio da classe Observador

    // implementa o método do Observador
    public void Update(Sujeito s) {
       
        
        if(s instanceof Sirene)// se o ConcreteSubject sirene for acionada
            System.out.println(" Estagiaria -  Tenho que recolher as provas!");
        else 
            if(s instanceof Professora) // se o ConcreteSubject professora for acionada
            System.out.println(" Estagiaria -  A professora disse: " + ((Professora) s).getComando());
    }
}

Classe Main

Tem como função de demostrar um exemplo de execução e troca de comportamento de objetos em tempo de execução pelo padrão Observer.

// classe principal

package br.padroesdeprojeto.observer.saladeaula; //pacote onde foi criado

// Classe principal do programa
public class Main {
    public static void main(String[] args){

        // inicializando os sujeito(ConcreteSubject), no caso uma Sirene e uma Professora, mas poderia haver varios sujeitos
        Sirene sirene = new Sirene();
        Professora professora = new Professora();
        
        // inicialização dos observadores(ConcreteObserver), no caso são quatro observadores, sendo tres alunos e uma estagiaria,
        // mas poderia haver varios observadores
        Observador aluno1 = new Aluno(); 
        Observador aluno2 = new Aluno();
        Observador aluno3 = new Aluno();
        Observador estagiaria = new Estagiaria();

        // adicionando-os como observadores do ConcreteSubject no caso a Sirene
        sirene.addObservador(aluno1);
        sirene.addObservador(aluno2);
        sirene.addObservador(aluno3);
        sirene.addObservador(estagiaria);

        // adicionando-os como observadores do ConcreteSubject no caso a Professora
        professora.addObservador(aluno1);
        professora.addObservador(aluno2);
        professora.addObservador(aluno3);
        professora.addObservador(estagiaria);
        
        // aplicando uma ação ao Subject Professora 
        professora.setComando("Vamos aplicar a prova!");
        
        System.out.println("\n 50 min depois\n IIIINNNFFFOOO");
        // aplicando uma ação ao Subject Sirene
        sirene.setAlertaSonoro(true);      
    }
}

Estrutura do código fonte

No código existe dois sujeitos concretos que implementa os métodos da interface Sujeito, dois observadores concretos que implementam a interface Observador. Os observadores visualizam as atualizações dos dois sujeitos concretos.

Estrutura do padrão Observer em relação ao código fonte

Referências

  1. GAMMA, Erich et al. Padrões de Projeto: soluções reutilizáveis de software orientado a objetos. – Porto Alegre: Bookman, 2000.
        2. Larman, Craig. Utilizando UML e padrões:uma introdução à análise e ao projeto orientados a objetos e ao desenvolvimento interativo. 3ª. Ed. Porto Alegre:Bookman, 2007.


Ligações externas