Domina los patrones de diseño fundamentales en JavaScript para crear código robusto, mantenible y escalable. Este artículo explora implementaciones prácticas de Singleton, Observer y Factory con ejemplos reales y casos de uso.
Diagrama de relaciones entre patrones Singleton, Observer y Factory
Contenido del Artículo
Singleton: Instancia Única
Garantiza una sola instancia globalmente accesible:
Instancia única
Solo una instancia en toda la aplicación
Acceso global
Punto de acceso centralizado
Casos de uso
Conexiones DB, Configuración, Logging
class DatabaseConnection {
constructor() {
if (DatabaseConnection.instance) {
return DatabaseConnection.instance;
}
this.connection = this.createConnection();
DatabaseConnection.instance = this;
}
createConnection() {
// Lógica compleja de conexión
console.log('Conexión establecida');
return { status: 'connected' };
}
query(sql) {
// Ejecutar consulta
return `Resultados de: ${sql}`;
}
}
// Uso
const db1 = new DatabaseConnection();
const db2 = new DatabaseConnection();
console.log(db1 === db2); // true
En JavaScript moderno, usar módulos ES6 suele ser mejor alternativa que Singleton clásico
Observer: Comunicación por Eventos
Patrón publicador-suscriptor para comunicación descentralizada:
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} recibió: ${data}`);
}
}
// Uso
const notificador = new Subject();
const obs1 = new Observer('Suscriptor 1');
const obs2 = new Observer('Suscriptor 2');
notificador.subscribe(obs1);
notificador.subscribe(obs2);
notificador.notify('Mensaje importante');
Factory: Creación Dinámica
Centraliza la creación de objetos sin exponer lógica interna:
class VehiculoFactory {
static crearVehiculo(tipo, config) {
switch(tipo) {
case 'auto':
return new Auto(config);
case 'moto':
return new Moto(config);
case 'camion':
return new Camion(config);
default:
throw new Error('Tipo de vehículo inválido');
}
}
}
class Auto { constructor({modelo, color}) { /* ... */ } }
class Moto { constructor({modelo, cilindrada}) { /* ... */ } }
// Uso
const miAuto = VehiculoFactory.crearVehiculo('auto', {
modelo: 'Sedán',
color: 'rojo'
});
Tipo Factory | Implementación | Cuando usar |
---|---|---|
Simple Factory | Función que retorna objetos | Creación básica |
Factory Method | Clase con método de creación | Creación con lógica |
Abstract Factory | Fábrica de fábricas | Familias de objetos relacionados |
Casos Reales en Desarrollo Web
Aplicación de patrones en proyectos modernos:
Singleton
Stores globales en aplicaciones React
Observer
Sistemas de eventos en Vue, Redux
Factory
Creación de componentes dinámicos
// Observer en React con Context API
const ThemeContext = React.createContext();
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(prev => prev === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
// Componentes suscritos
const Header = () => {
const { theme } = useContext(ThemeContext);
return <header className={`header-${theme}`}>...</header>;
};