Combinando patrones Singleton y Factory para crear un logger
Resumen
Crear un logger eficiente en JavaScript es posible combinando dos patrones esenciales: Singleton y Factory. Esta combinación permite gestionar registros o logs de manera centralizada y versátil, adaptándose fácilmente a las necesidades específicas del proyecto.
¿Qué es el patrón singleton y cómo implementarlo en JavaScript?
El patrón Singleton asegura que una clase tenga una única instancia en la aplicación. En JavaScript, puedes lograr esto definiendo una clase que verifica si ya existe una instancia antes de crear una nueva.
Al usar Singleton, se asegura que cada vez que se instancia la clase Logger sea la misma instancia, centralizando los logs en un solo lugar.
¿Cómo funciona el patrón factory para crear diferentes tipos de loggers?
El patrón Factory permite crear diferentes tipos de objetos a partir de una sola clase o interfaz. Así puedes crear fácilmente loggers específicos según tus necesidades.
Este ejemplo muestra cómo crear dos tipos de logger con un Factory:
¿Cómo combinar los patrones singleton y factory en una aplicación real?
Integrando ambos patrones, puedes manejar logs efectivamente en diferentes modalidades (consola, archivo, etc.), sin perder la centralización.
Aquí está el archivo principal para implementar estos conceptos combinados:
constLoggerFactory=require('./loggerFactory');constLogger=require('./logger');const loggerInstance =newLogger();const consoleLogger =LoggerFactory.createLogger('console');const fileLogger =LoggerFactory.createLogger('file');consoleLogger.log('esto es un mensaje de en consola');fileLogger.log('esto es un mensaje de log en archivo');loggerInstance.getLogs().forEach(log=>console.log(log));
Al ejecutar este código, verás cómo cada tipo de logger maneja su función específica, y todos los logs se mantienen en una ubicación centralizada gracias al patrón singleton.
¿Te animas a completar el reto propuesto? Cuéntame tus resultados en los comentarios.
Combinando patrones Singleton y Factory para crear un logger
y automaticamente esta agregando los logs en el archivo.
Mi solución al reto. Yo toda la logica la agregue directo desde la clase FileLogger, donde al inicio reseteo el archivo a contenido en blanco y despues tengo una función llamada "saveLog(msg)" que es privada, que me permite guardar todos los logs en el archivo
que es un constructor, y como mezclar los patrones?
Un constructor es simplemente el método que dispara la vida de un objeto; es el momento exacto en que la clase dice "aquí estoy" y reserva su espacio en memoria.
Para mezclarlos, imagina que la Factory es el recepcionista que decide qué logger necesitas, mientras que el Singleton es el único gerente que garantiza que, sin importar cuántas veces pidas un logger, siempre recibas la misma instancia. ¿Qué crees que pasaría si el constructor fuera público en este escenario?
Para evitar borrar los registros previos y mantener el historial de logs, lo ideal es inicializar this.logssolo la primera vez que se crea la instancia. Así:
classLogger{constructor(){if(!Logger.instance){this.logs=[];// Solo se inicializa una vezLogger.instance=this;}returnLogger.instance;}log(message){const timestamp =newDate().toISOString();this.logs.push(`${timestamp}: ${message}`);console.log(`${timestamp}: ${message}`);}getLogs(){returnthis.logs;}}
Si quisiéramos escribir en un archivo los logs provenientes del FileLogger podríamos hacer lo siguiente:const fs = require('fs');const path = require('path');const Logger = require('./logger');
const loggerInstance = new Logger(); // Singleton instance
class ConsoleLogger { constructor() { this.logger = loggerInstance; }
log(message) { this.logger.log(message); }}
class FileLogger { constructor(filePath = path.join(__dirname, 'logs.txt')) { this.logger = loggerInstance; this.filePath = filePath; }
log(message, level = 'info') { this.logger.log(message);
const timestamp = new Date().toISOString(); const formattedMessage = \[${timestamp}] \[${level.toUpperCase()}] ${message}\n;
fs.appendFileSync(this.filePath, formattedMessage, 'utf8'); this.logger.log(message, level); // Registrar en el logger base }}
class LoggerFactory { static createLogger(type) { switch (type) { case 'console': return new ConsoleLogger(); case 'file': return new FileLogger(); default: throw new Error('Invalid logger type'); } }}
module.exports = LoggerFactory;