Um pouco do padrão
Esse padrão é simples, usado para comunicação entre objetos, o principal objetivo está em definir como notificaremos vários objetos quando acontecer um evento com outro objeto, por exemplo, sempre que uma venda for aprovada, devemos enviar um e-mail para o cliente e criar uma nota fiscal.
Existem dois principais componentes nesse padrão, o Observável e o Observador, vamos conhecer mais um pouco sobre eles.
Observable
Representa o objeto que será observado, em nosso exemplo a Venda, sempre que mudar de status devemos notificar todos que escutam esse objeto.
Observable, tem métodos para adicionar, remover e notificar os observadores.
O objeto que será observado por outros por padrão ele deverá ter algumas características como:
- Ter uma referência para todos os seus observadores
- Observadores podem se inscrever e desinscrever em tempo de execução
Observers
Representa o objeto que será notificado quando um observável disparar suas notificações, ele deve ter um meio de receber as notificações do seu observável.
Na implementação padrão, temos uma interface que será implementada por todos que querem receber essa "notificação", essa interface tem apenas um método que obriga seu dependente a implementar.
Obs: Existe outros padrões que são parecidos como pub/sub
Quando Implementar?
Quando existir uma necessidade informar a outros objetos que um objeto teve alteração.
Um exemplo
Quando um e-commerce recebe um pedido de compra e esse pedido é "APROVADO" com esse status precisamos fazer algumas coisas como, enviar e-mail de confirmação para cliente e vendedor
Como implementar?
Nesse exemplo vamos usar:
- PropertyChangeListener
- PropertyChangeSupport
- PropertyChangeEvent
Cenário
Nosso cenário teremos uma rotina de vendas e sempre que recebermos uma venda deveremos disparar um e-mail para o comprador e disparar a rotina de criar nota fiscal.
Classe de negócio
Começaremos criando a primeira classe, classe que representará uma ordem de venda, ela será nossa entidade central.
public class Order {
private String client;
private BigDecimal amount;
private String status;
}
Criando um observador que envia e-mail
Esse observador receberá as notificações da Order, usaremos a interface PropertyChangeListener
para deixá-lo apto a receber essas notificações.
public class SendEmailOrderObserver implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println("Disparar email para cliente");
}
}
Note que essa interface tem apenas um método, que recebe um PropertyChangeEvent e com ele conseguiremos ter acesso ao objeto antigo e o novo.
PropertyChangeEvent
Classe que será enviada como argumento para todos os observadores assinados, normalmente esse objeto contém um nome
, um valor antigo
e um valor novo
, com essas informações podemos fazer várias regras de negócio.
Criando Observável
Essa classe será responsável de registrar, remover e disparar notificações para todos os observadores
registrados, aqui vamos levar em consideração uma regra do Padrão, "todos os observadores podem inscrever-se e se desinscrever".
public class OderObserver {
private PropertyChangeSupport support;
public OderObserver() {
this.support = new PropertyChangeSupport(this);
}
/*
* Método para registrar Observadores
*/
public void addListener(PropertyChangeListener listener){
this.support.addPropertyChangeListener(listener);
}
/*
* Método para remover Observadores
*/
public void removeObserver(PropertyChangeListener observer){
this.changeSupport.removePropertyChangeListener(observer);
}
/*
* Método para que receerá uma nova orden e notificará a todos
*/
public void notification(Order order){
this.support.firePropertyChange("order", null, order);
}
}
Acessando objeto notificado
Como vimos o objeto que receberemos é um Order
agora vamos ver como podemos fazer para acessar os valores desse objeto, abaixo vamos mostrar como está atualmente o código
@Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println("Disparar email para cliente");
}
Podemos usar a conversão para ajudar, como no trecho abaixo:
@Override
public void propertyChange(PropertyChangeEvent evt) {
System.out.println("Disparar email para cliente");
Order order = (Order) evt.getNewValue();
System.out.println("Valor "+ order.getAmount());
}
Pronto agora temos acesso a todos os atributos do objeto notificado.
Observador Assincrono
Por padrão essa rotina fica sempre dentro da mesma thread, se tivermos vários observadores teremos que esperar o primeiro fazer para deṕois o segundo fazer, isso pode ser um problema em um projeto real, portanto agora vamos ver como podemos usar uma outra classe bem legal do Java chamada de CompletableFuture, ela nos ajudará a escrever um Observador Assíncrono.
O CompletableFuture
como o próprio nome já diz, completa no futuro, com essa classe podemos pedir que o java execute uma operação em outra thread dando a possibilidade de executar coisas em paralelo.
Em nosso exemplo, vamos mudar um pouco nossa implementação para usarmos essa classe.
@Override
public void propertyChange(PropertyChangeEvent evt) {
CompletableFuture.runAsync(()->{
System.out.println("Disparar email para cliente");
Order order = (Order) evt.getNewValue();
System.out.println("Valor "+ order.getAmount());
}
}
Conclusão
Essa solução ajuda a escrever componentes desacoplados, ajudando na redução do escopo de cada Classe/Component.
Repositório: https://github.com/cassunde/spring_boot_quarkus/tree/master/event/java/property
vou ficando por aqui até a próxima...
Top comments (0)