Event Bus y el patrón Observer en TypeScript: de la teoría a la práctica
El desarrollo web moderno requiere una arquitectura flexible y escalable. Dos patrones clave que ayudan a organizar la interacción entre componentes son Event Bus y Observer. En este artículo analizaremos su implementación en TypeScript, sus ventajas y escenarios prácticos de uso.
¿Qué es el patrón Observer?
El patrón Observer (Observador) es un patrón de diseño de comportamiento que define una dependencia de "uno a muchos" entre objetos. Cuando un objeto (publicador) cambia su estado, todos los objetos dependientes (suscriptores) son notificados y actualizados automáticamente.
Elementos principales del patrón:
- Subject (Publicador) — objeto que rastrea los cambios y notifica a los suscriptores.
- Observer (Observador) — objeto que se suscribe a los cambios del publicador.
- Event Bus (Bus de eventos) — mecanismo centralizado que gestiona las suscripciones y el envío de eventos entre componentes.
Implementación de Event Bus en TypeScript
TypeScript ofrece excelentes capacidades para una tipificación estricta, lo que hace que la implementación de Event Bus sea segura y predecible. Veamos una implementación básica:
type EventHandler<T = any> = (payload: T) => void;
class EventBus { private listeners: Map<string, EventHandler[]> = new Map();
// Suscripción a un evento subscribe<T>(event: string, handler: EventHandler<T>): void { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event)!.push(handler); }
// Cancelar suscripción a un evento unsubscribe<T>(event: string, handler: EventHandler<T>): void { const handlers = this.listeners.get(event); if (handlers) { this.listeners.set( event, handlers.filter(h => h !== handler) ); } }
// Publicación de un evento emit<T>(event: string, payload: T): void { const handlers = this.listeners.get(event); if (handlers) { handlers.forEach(handler => handler(payload)); } }
// Limpiar todas las suscripciones clear(): void { this.listeners.clear(); }}
export const eventBus = new EventBus();Ejemplo de uso con eventos tipificados
Para mejorar la seguridad de tipos, se pueden definir interfaces de eventos:
// Definimos los tipos de eventosinterface AppEvents { 'user:login': { userId: string; timestamp: number }; 'user:logout': { userId: string }; 'data:update': { id: string; data: unknown }; 'notification:show': { message: string; type: 'success' | 'error' | 'info' };}
// Creamos un bus tipificadoclass TypedEventBus { private listeners: Map<string, Function[]> = new Map();
on<K extends keyof AppEvents>( event: K, handler: (payload: AppEvents[K]) => void ): void { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event)!.push(handler); }
emit<K extends keyof AppEvents>( event: K, payload: AppEvents[K] ): void { const handlers = this.listeners.get(event); if (handlers) { handlers.forEach(handler => handler(payload)); } }
off<K extends keyof AppEvents>( event: K, handler: (payload: AppEvents[K]) => void ): void { const handlers = this.listeners.get(event); if (handlers) { this.listeners.set( event, handlers.filter(h => h !== handler) ); } }}
export const typedBus = new TypedEventBus();Ejemplo práctico: sistema de notificaciones
Consideremos un escenario real: la creación de un sistema de notificaciones utilizando Event Bus:
También en la biblioteca
Turbine Kotlin: guía completa con ejemplos prácticos
Tokens JWT en Java: guía completa para trabajar con JSON Web Tokens
Pruebas en PHP: resumen de frameworks y herramientas (PHPUnit, Pest, Codeception)
Trabajo con Excel en TypeScript: bibliotecas, herramientas y ejemplos de código