Today I Learned 06/05/2022
Eventos de domínio
A essência de um evento de domínio é que você o usa para capturar coisas que podem desencadear uma mudança no estado do aplicativo que você está desenvolvendo. Esses objetos de evento são processados para causar alterações no sistema e armazenados parar fornecer um AuditLog
Fowler, Martin
Ou seja quando algo acontece no sistema eu posso baseado nesse evento executar uma operação e armazenar o evento para um caso de auditoria no futuro
Todo evento deve ser representado em uma ação representada no passado, exemplo UserCreated
Quando utilizar
Normalmente um domain event deve ser utilizado quando queremos notificar outros Bounded Contexts de uma mudança de estado
exemplo: Um sistema de E-commerce quando um pedido é criado, podemos emitir um evento de OrderPlaced
e então o boundedContext de emissão de notas fiscais vai escutar esse evento e emitir a nota para aquele pedido
Componentes
- Event Tem uma data e hora, e contem o que aconteceu naquela data e hora Ex: produto com nome X mudou para Y
- Handler Executa o processamento quando o evento é chamado Ex: depois de criar um usuário eviar um email, a parte de enviar email é um handler
- Event Dispatcher Responsável por armazenar e executar os handlers de um evento quando ele é disparado
Dinâmica
- Criar um "Event Dispatcher"
- Criar um "Evento"
- Criar um "Handler" para o "Evento"
- Registrar o Evento, juntamente com o Handler no "Event Dispatcher"
E ai quando dermos um notify
no Event dispatcher
passando o evento, todos os handlers
serão executados
Implementação
primeiro vamos criar as nossas interfaces que serão implementadas pelo dispatcher, pelos eventos e pelos handlers
export interface EventInterface<T=any> {
dateTimeOcurred: Date;
eventData: T;
}
export interface EventHandlerInterface<T extends EventInterface=EventInterface>{
handle(event: T): void;
}
export interface EventDispatcherInterface{
notify(event: EventInterface): void;
register(eventName: string, eventHandler: EventHandlerInterface): void;
unregister(eventName: string, eventHandler: EventHandlerInterface): void;
unregisterAll(): void;
}
e ai vamos criar a nossa classe de event dispatcher
export class EventDispatcher implements EventDispatcherInterface{
private eventHandlers: { [eventName: string]: EventHandlerInterface[] } = {};
get getEventsHandler(): { [eventName: string]: EventHandlerInterface[] }{
return this.eventHandlers;
}
notify(event: EventInterface): void {
const eventName = event.constructor.name;
if(this.eventHandlers[eventName]){
this.eventHandlers[eventName].forEach(eventHandler => {
eventHandler.handle(event);
})
}
}
register(eventName: string, eventHandler: EventHandlerInterface<EventInterface>): void {
if (!this.eventHandlers[eventName]) {
this.eventHandlers[eventName] = [];
}
this.eventHandlers[eventName].push(eventHandler);
}
unregister(eventName: string, eventHandler: EventHandlerInterface<EventInterface>): void {
if (!this.eventHandlers[eventName]) {
throw new Error(`${eventName} event does not exist.`);
}
const index = this.eventHandlers[eventName].indexOf(eventHandler);
if (index !== -1){
this.eventHandlers[eventName].splice(index, 1);
}else{
throw new Error(`${eventName} event handler not registered.`);
}
}
unregisterAll(): void {
this.eventHandlers = {};
}
}
Nessa classe vamos ter um objeto com os event handlers e vamos verificar se o evento ao qual o handler quer ser registrado já existe, se já existir vamos somente adicionar o handler ao evento, se não existir vamos criar o evento e adicionar o handler em seguida. Também nessa classe temos o método notify, que recebe o evento e percorre todos os handlers associados a ele executando o método handle
E ai vamos criar o nosso evento
export class ProductCreatedEvent implements EventInterface{
dateTimeOcurred: Date;
eventData: any;
constructor(eventData: any){
this.dateTimeOcurred = new Date();
this.eventData = eventData;
}
}
e o nosso handler para esse evento que nesse caso será o de enviar email quando o produto for criado
export class SendEmailWhenProductIsCreatedHandler implements EventHandlerInterface<ProductCreatedEvent>{
handle(event: ProductCreatedEvent): void {
console.log("Sending email to user...")
}
}
e para fazermos isso funcionar basta a seguinte implementação
const eventDispatcher = new EventDispatcher();
const eventHandler = new SendEmailWhenProductIsCreatedHandler();
const spyEventHandler = jest.spyOn(eventHandler, "handle");
eventDispatcher.register("ProductCreatedEvent", eventHandler)
const productCreatedEvent = new ProductCreatedEvent({
name: "Product 1",
description: "Product 1 description",
price: 100
});
eventDispatcher.notify(productCreatedEvent)
então toda vez que um novo produto for criado basta a chamarmos a função notify que executa todos os handlers associados ao evento que ela recebeu
Ainda estou aprendendo sobre DDD e se quiser ver melhor o código pode dar uma olhada nesse Repositório
Top comments (0)