Dúvida sobre padrão de projeto Observer e implementação de Listeners

8 respostas
B

Minha internet é bloqueada, não consigo pesquisar sobre isso no google. Peguei um livro na biblioteca sobre isso, mas o cara que tá com ele ainda não devolveu. :(

Eu possuo uma classe Celeiro, uma classe Abstrata Ração, que tem 2 filhos (Milho e Soja) e uma interface que é um listener.

Classe Celeiro, não colei todos os métodos senão fica muito grande. O que acontece é que quando adicionar um saco eu quero notificar o listener de que um saco foi adicionado.
public class Celeiro<T extends Racao> {

    private int id;
    private int qtdadeMax;
    private int qtdAtual;
    private ArrayList<Racao> estoque = new ArrayList<Racao>();
    private ArrayList<Listener> olheiro = new ArrayList<Listener>();

    public Celeiro(int id, int qtdadeMax) {
        this.id = id;
        this.qtdadeMax = qtdadeMax;
    }

    public void addListener(Listener l) {
        olheiro.add(l);
    }

    public void removeListener(Listener l) {
        olheiro.remove(l);
    }

    public void adicionaSaco(T r) {       
        if (qtdAtual < qtdadeMax) {
            estoque.add(r);
            qtdAtual++;
            notificacaoNovoSaco(o);
        }
    }
    public void notificacaoNovoSaco(EventObject o) {
        for (Listener listener : olheiro) {
            listener.entrouNovoSaco(o);
        }
    }

Interface Listener:

public interface Listener {
    

    void entrouNovoSaco(EventObject objeto);

    void chegouNaMetade(EventObject objeto);

    void chegouNoFinal(EventObject objeto);
}

Listener que vai implementar a interface:

public class EchoListener implements Listener {

    public void entrouNovoSaco(EventObject objeto) {
        System.out.println("Saco Adicionado no Celeiro: ");
    }

    public void chegouNaMetade(EventObject objeto) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void chegouNoFinal(EventObject objeto) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

O que está acontecendo é que no metodo da classe celeiro ele pede um EventObject como parâmetro e eu nao sei quem eu deveria passar como parâmetro no método. Eu já fiz esse padrão observer com uma string, mas o construtor da classe recebia uma string também, aí era de fácil compreensão. "Observe que nesses métodos é enviado um objeto EventObject. Ao criar um objeto desses, passe como parâmetro o objeto Celeiro." Tentei passar e não rolou também.

E quando entrar um saco novo, ele quer que identifique de qual celeiro que veio o saco. Deveria ter um atributo do tipo Celeiro na classe EchoListener pra isso e colocar no método de notificação? Tem essa observação aqui:

Espero que com isso possam me ajudar, não sei se consegui explicar direito a parada. To perdido.
:P

Valeu galera.

8 Respostas

Lavieri

o interessante é que vc crie um evento proprio, caso queira propriedades adcionais, caso contrario é assim

public class Celeiro<T extends Racao> {   
  
    private int id;   
    private int qtdadeMax;   
    private int qtdAtual;   
    private ArrayList<Racao> estoque = new ArrayList<Racao>();   
    private ArrayList<Listener> olheiro = new ArrayList<Listener>();   
  
    public Celeiro(int id, int qtdadeMax) {   
        this.id = id;   
        this.qtdadeMax = qtdadeMax;   
    }   
  
    public void addListener(Listener l) {   
        olheiro.add(l);   
    }   
  
    public void removeListener(Listener l) {   
        olheiro.remove(l);   
    }   
  
    public void adicionaSaco(T r) {         
        if (qtdAtual < qtdadeMax) {   
            estoque.add(r);   
            qtdAtual++;   
            fireAdcionaSacoEvent();
        }   
    }

    private void fireAdcionaSacoEvent() {
        EventObject evento = new EventObject(this);
        for (Listener listener : olheiro) {   
            listener.entrouNovoSaco(evento);
        }
    }
}

vc pode extender EventObject, e criar um CeleiroEvent
com propriedades propria, isso c vc quiser dar alguma informação na hora de disparar o evento, e se o fizer, vc deve enviar o CeleiroEvent no lugar do ObjectEvent ... alem de mudar a assinatura do Listner para receber CeleiroEvent no lugar de ObjectEvent ... por exemplo

public class CeleiroEvent extends EventObject {
     private Racao racao;
     CeleiroEvent(Celeiro c) {
          super(c);
     }
     CeleiroEvent(Celeiro c, Racao r) {
         super(c);
         this.racao = r;
     }
     public Racao getRacao() {
         return this.racao;
     }
}
B

Lavieri, você é uma máquina de respostas
hahahaha :smiley:
Vou testar isso e depois posto aqui.

Valeu brother!

Lavieri

Se vc utilizar a segunda opção e criar seu proprio evento... vc terá mais funcionalidades como...

Mudando seu Listner

public interface Listener {   
       
  
    void entrouNovoSaco(CeleiroEvent c);   
  
    void chegouNaMetade(CeleiroEvent c);   
  
    void chegouNoFinal(CeleiroEvent c);   
}

Mudando o fireAdcionaSacoEvent()

private void fireAdcionaSacoEvent(T racao) {   
        CeleiroEvent evento = new CeleiroEvent(this,racao);   
        for (Listener listener : olheiro) {     
            listener.entrouNovoSaco(evento);   
        }   
    }

mudando o adicionaSaco(T r)

public void adicionaSaco(T r) {           
        if (qtdAtual < qtdadeMax) {     
            estoque.add(r);     
            qtdAtual++;     
            fireAdcionaSacoEvent(r);   
        }     
    }

agora vc tem mais informações no seu evento... por exemplo

public class EchoListener implements Listener {   
  
    public void entrouNovoSaco(CeleiroEvent c) {   
        System.out.println("Novo saco da racao '" + c.getRacao() +"' adcionado ao celeiro '" + c.getSource() + "' "
        + " nova quantidade = " + ((Celeiro)c.getSource()).getQuantidade() );   
    }   
    //... outros métodos
}
B

CAra, eu fiz como você sugeriu e acho que fechou muito certinho.

Mas por exemplo, no celeiroEvento se eu crio o método getId, quando eu chamo retorna 0. Porque eu queria que pegasse o método do Celeiro. Oque eu fiz foi usar um getSource como você tinha mostrado e implementar um método toString na classe Celeiro. É sussa fazer assim? (Agora vi sua atualização sobre o cast do getSource pra chamar os métodos. Beleza! :smiley:

Outra coisa, na classe interface e na classe que implementa a interface da o seguinte aviso:
“Exportando tipo não público através de API pública.” Como faço pra tirar esses aviso? O que tá rolando?

Valeu pela força ae cara, você tem me ajudado bastante.

B

Botei a classe do CeleiroEvent como pública e foi, antes não tinha definição nenhuma.

:stuck_out_tongue:

Achei que ele subentendesse como pública.

Lavieri

[BlacK:
]CAra, eu fiz como você sugeriu e acho que fechou muito certinho.

Mas por exemplo, no celeiroEvento se eu crio o método getId, quando eu chamo retorna 0. Porque eu queria que pegasse o método do Celeiro. Oque eu fiz foi usar um getSource como você tinha mostrado e implementar um método toString na classe Celeiro. É sussa fazer assim? (Agora vi sua atualização sobre o cast do getSource pra chamar os métodos. Beleza! :D

é que o método getSource() é da classe EventObject, e la esta defindo que o retorno é um Object, portanto é preciso fazer o cast, para poder utilizar métodos do celeiro…

[BlacK:
]Outra coisa, na classe interface e na classe que implementa a interface da o seguinte aviso:
“Exportando tipo não público através de API pública.” Como faço pra tirar esses aviso? O que tá rolando?

Valeu pela força ae cara, você tem me ajudado bastante.

tb axei q era direto, eu sempre declaro publicos, por isso nao tenho como saber, e nao estou com IDE aqui para ver c compila…

Outra coisa… quando vc precisar de escutas para tomar decioes, coloque uma antes do processo e outra no fim… por exemplo

public void adicionaSaco(T r) { fireBeforeAdcionaSacoEvent(r); if (qtdAtual < qtdadeMax) { estoque.add(r); qtdAtual++; fireAfterAdcionaSacoEvent(r); } }

aqui neste caso, vc poderia interceptar o evento antes dele ser concluido… checando em um dos listners, por exemplo, se a racao esta estragada, e estando, lancar uma excecao, paralizando o processo de adcionar a racao, antes mesmo dele ir pra o estoque …

seria + ou - com triggers de banco de dados… as vezes é util…

B

Valeu pelo insight ae cara, deu tdo certo.

Voltei a usar o EventObject na classe listener:

public interface Listener {

    void entrouNovoSaco(EventObject objeto);

    void chegouNaMetade(EventObject objeto);

    void chegouNoFinal(EventObject objeto);
}

E usei um cast na classe que realiza a interface:

public class EchoListener implements Listener {

    public void entrouNovoSaco(EventObject objeto) {
        int id = ((Celeiro) objeto.getSource()).getId();
        int qtdSacos = ((Celeiro) objeto.getSource()).getQtdAtual();
        System.out.println("Entrou novo saco no celeiro: " + id + " Qtd de sacos: " + qtdSacos);
    }

    public void chegouNaMetade(EventObject objeto) {
        int id = ((Celeiro) objeto.getSource()).getId();
        System.out.println("Chegou na metade do celeiro: " + id);
    }

    public void chegouNoFinal(EventObject objeto) {
        int id = ((Celeiro) objeto.getSource()).getId();
        System.out.println("Chegou no final do celeiro: " + id);
    }
}
Fechou tudo certo também :D
Lavieri

[BlacK:
]Valeu pelo insight ae cara, deu tdo certo.

Voltei a usar o EventObject na classe listener:

Fechou tudo certo também
:smiley:

por nada ^^ … so vale a pena fazer um EventProprio, quando é de interesse passar mais argumentos que apenas o Objeto fonte do evento…

outra coisa… c vc estiver usando Collection para guardar o estoque, vc não precisa de uma veriável para guardar quantidade… basta utilizar estoque.size()

… boa sorte ai no seu projeto

Criado 13 de março de 2009
Ultima resposta 13 de mar. de 2009
Respostas 8
Participantes 2