Observer
Problema
Sección titulada «Problema»Si el código que crea un usuario tiene que llamar directamente a enviarBienvenida(), registrarEnAnalytics() y sincronizarConCRM(), ese servicio termina acoplado a todo lo que “reacciona” a la creación de un usuario. Agregar un quinto listener implica tocar ese archivo otra vez. Observer invierte la relación: el que dispara el evento no conoce a los que escuchan.
Ejemplo: EventEmitter de Node
Sección titulada «Ejemplo: EventEmitter de Node»import { EventEmitter } from "node:events"
export const eventos = new EventEmitter()import { eventos } from "@/libs/events"
export async function crearUsuario(datos: DatosUsuario) { const usuario = await db.usuario.create({ data: datos }) eventos.emit("user:created", { id: usuario.id, email: usuario.email }) return usuario}import { eventos } from "@/libs/events"
eventos.on("user:created", ({ email }) => enviarBienvenida(email))eventos.on("user:created", ({ id }) => registrarEnAnalytics(id))crearUsuario no sabe (ni le importa) cuántos listeners hay ni qué hacen. Agregar uno nuevo es agregar un .on() en otro archivo.
El mismo patrón, en todas partes
Sección titulada «El mismo patrón, en todas partes»addEventListener('click', handler)del DOM es Observer: el botón no sabe qué código reacciona al click.- Una store de Zustand o Redux notifica a cada componente suscrito cuando el estado cambia — los componentes son observers del store.
const useStore = create<Estado>((set) => ({ count: 0, incrementar: () => set((s) => ({ count: s.count + 1 }))}))// Cada componente que llama useStore() se suscribe y re-renderiza cuando el estado cambia.Cuándo NO usarlo
Sección titulada «Cuándo NO usarlo»Si solo hay un emisor y un único receptor que siempre reacciona, una llamada de función directa es más fácil de seguir que un evento. Los eventos dificultan trazar “quién reacciona a esto” cuando se abusan en un codebase grande — reservalos para cuando de verdad hay múltiples receptores desacoplados, o cuando el emisor no debería conocer a sus consumidores.