Una Implementación Simple del Patrón Publicar-Suscribir

El patrón publicador-suscriptor (pub/sub) es ampliamente utilizado en el desarrollo de software, especialmente para comunicación entre componentes, sistemas de micro-frontends y comunicación entre aplicaciones secundarias.

A continuación se presenta una implementación simplificada de este patrón:

  • Susripción
  • Restricción de tipos durante la inicialización
  • Publicación

La restricción de tipos permite que los suscriptores y publicadores conozcan de antemano qué tipos de eventos están disponibles, eivtando el uso de tipos desconocidos por alguna de las partes.

type Manejador<T> = (dato?: T) => void;

export default class EventBus<T> {
  // Almacén de suscriptores por tipo de evento
  public manejadores: Record<string, Manejador<T>[]> = {};
  // Tipos de eventos permitidos
  public tiposPermitidos: string[] | undefined = undefined;

  constructor(tipos?: string[]) {
    this.tiposPermitidos = tipos;
  }

  // Registrar un suscriptor
  agregarSuscriptor(tipo: string, manejador: Manejador<T>) {
    const tipos = this.tiposPermitidos;

    if (tipos && !tipos.includes(tipo)) {
      console.warn(`No se pudo crear el suscriptor para "${tipo}". Los tipos permitidos son: ${tipos.join(', ')}`);
      return;
    }

    if (typeof manejador !== 'function') {
      console.warn('Error al crear suscriptor: el segundo parámetro debe ser una función');
      return;
    }

    if (!this.manejadores[tipo]) {
      this.manejadores[tipo] = [];
    }

    this.manejadores[tipo].push(manejador);
  }

  // Suscribirse solo una vez, se elimina automáticamente después de ejecutarse
  agregarSuscriptorUnico(tipo: string, manejador: Manejador<T>) {
    if (typeof manejador !== 'function') {
      console.warn('Error al crear suscriptor: el segundo parámetro debe ser una función');
      return;
    }

    constenvoltorio = (dato?: T) => {
      manejador(dato);
      this.eliminarSuscriptor(tipo,envoltorio);
    };

    this.agregarSuscriptor(tipo,envoltorio);
  }

  // Eliminar un suscriptor específico
  eliminarSuscriptor(tipo: string, manejador: Manejador<T>) {
    if (this.manejadores[tipo]) {
      this.manejadores[tipo] = this.manejadores[tipo].filter(fn => fn !== manejador);
    }
  }

  // Publicar un evento, ejecuta todas las funciones suscritas
  notificar(tipo: string, dato?: T) {
    const tipos = this.tiposPermitidos;

    if (tipos && !tipos.includes(tipo)) {
      console.warn(`No se puede publicar "${tipo}". Los tipos permitidos son: ${tipos.join(', ')}`);
      return;
    }

    if (this.manejadores[tipo]) {
      this.manejadores[tipo].forEach(fn => {
        fn(dato);
      });
    }
  }
}

Ejemplo de uso

Inicializar y exportar una instancia del bus de eventos (en sistemas de micro-frontends, pasar esta instancia a las aplicaciones secundarias). Esto permite la comunicación entre diferentes partes de la aplicación.

// Inicialización
export const eventosMaestro = new EventBus(['MICRO_APP_MONTADO', 'MICRO_ACCION']);

// Suscripción
eventosMaestro?.agregarSuscriptor('MICRO_ACCION', (parametros) => {
  // Ejecutar alguna acción
});

// Publicación
eventosMaestro.notificar('MICRO_ACCION', {
  //...parametros
});

Este patrón proporciona un acoplamiento débil entre componentes, permitiendo que el publicador y el suscriptor operen de forma independiente sin conocerse directamente.

Etiquetas: TypeScript patrones-de-diseño JavaScript programación-reactiva arquitectura-de-software

Publicado el 7-19 02:38