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

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. :frowning:

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.

[code]public class Celeiro {

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);
    }
}[/code]

Interface Listener:

[code]public interface Listener {

void entrouNovoSaco(EventObject objeto);

void chegouNaMetade(EventObject objeto);

void chegouNoFinal(EventObject objeto);

}[/code]

Listener que vai implementar a interface:

[code]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.");
}

}[/code]

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.
:stuck_out_tongue:

Valeu galera.

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

[code]public class Celeiro {

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);
    }
}

}[/code]

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; } }

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

Valeu brother!

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

Mudando seu Listner

[code]public interface Listener {

void entrouNovoSaco(CeleiroEvent c);   

void chegouNaMetade(CeleiroEvent c);   

void chegouNoFinal(CeleiroEvent c);   

} [/code]

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

[code]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

} [/code]

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.

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.

[quote=[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[/quote]

é 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…

[quote=[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.[/quote]

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…

Valeu pelo insight ae cara, deu tdo certo.

Voltei a usar o EventObject na classe listener:

[code]public interface Listener {

void entrouNovoSaco(EventObject objeto);

void chegouNaMetade(EventObject objeto);

void chegouNoFinal(EventObject objeto);

}[/code]

E usei um cast na classe que realiza a interface:

[code]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);
}

}
[/code]
Fechou tudo certo também
:smiley:

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

Voltei a usar o EventObject na classe listener:

Fechou tudo certo também
:smiley:
[/quote]

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