Patrón Factory, Inmutabilidad con Object.freeze() y Buenas Prácticas
Aprende a encapsular la creación de objetos con el Patrón Factory, blindar estados con Object.freeze() y aplicar las mejores prácticas de la industria en JS.
El Patrón Factory (Factoría) en JavaScript
El Patrón Factory centraliza y oculta la lógica de creación de objetos. En lugar de que el código cliente tenga que saber qué clase instanciar con new y cómo configurarla, simplemente le pide a la factoría: "dame un usuario de tipo admin" o "dame una pasarela de pago para Colombia".
En JavaScript, una factoría puede ser un método estático de una clase (UsuarioFactory.crear()) o una simple función pura que retorna objetos (conocida como Factory Function).
Blindaje e Inmutabilidad con `Object.freeze()`
Una de las mejores prácticas en aplicaciones críticas consiste en evitar que los datos de configuración o estados de negocio sean alterados accidentalmente.
| Método de Seguridad | ¿Permite Añadir? | ¿Permite Borrar? | ¿Permite Modificar Valores? |
|---|---|---|---|
Object.freeze(obj) |
❌ No | ❌ No | ❌ No (Inmutable al 100%) |
Object.seal(obj) |
❌ No | ❌ No | ✔ Sí (Solo existentes) |
Decálogo de Buenas Prácticas de POO en JavaScript
- 1. Usa campos privados (`#`): Olvídate de los guiones bajos como
_propiedad; utiliza la sintaxis nativa de ES2022. - 2. Favorece la composición sobre la herencia: Evita jerarquías de más de dos niveles con
extends. - 3. Un archivo por clase con ESM: Exporta cada clase en su propio archivo
.jso.mjs. - 4. Arrow Functions para callbacks: Evita problemas con
thisusando funciones flecha para eventos y promesas.
⚡ Factoría de Perfiles de Usuario con Inmutabilidad Object.freeze()
Ejecuta el código en el Sandbox y observa la creación estandarizada y la protección contra mutaciones:
// 1. Roles del Sistema Inmutables (Sellados con freeze)
const ROLES = Object.freeze({
ADMIN: "administrador",
ESTUDIANTE: "estudiante",
DOCENTE: "docente"
});
// 2. Clases Especializadas de Usuario
class UsuarioBase {
#id;
constructor(id, nombre, email, rol, permisos) {
this.#id = id;
this.nombre = nombre;
this.email = email;
this.rol = rol;
// Congelamos la lista de permisos para que nadie pueda inyectar privilegios
this.permisos = Object.freeze([...permisos]);
}
tienePermiso(permiso) {
return this.permisos.includes(permiso);
}
obtenerPerfil() {
return `[#${this.#id}] ${this.nombre} (${this.rol.toUpperCase()}) | Permisos: [${this.permisos.join(", ")}]`;
}
}
// 3. Patrón Factory (Factoría Centralizada)
class UsuarioFactory {
static #contadorId = 1;
static crearUsuario(tipo, nombre, email) {
const id = UsuarioFactory.#contadorId++;
switch (tipo.toLowerCase()) {
case 'admin':
return new UsuarioBase(
id,
nombre,
email,
ROLES.ADMIN,
['leer', 'crear', 'editar', 'eliminar', 'configurar_sistema']
);
case 'docente':
return new UsuarioBase(
id,
nombre,
email,
ROLES.DOCENTE,
['leer', 'crear', 'editar', 'calificar']
);
case 'estudiante':
return new UsuarioBase(
id,
nombre,
email,
ROLES.ESTUDIANTE,
['leer', 'enviar_tareas']
);
default:
throw new Error(`Tipo de usuario desconocido: ${tipo}`);
}
}
}
// ==========================================
// PRUEBA EN EL SANDBOX
// ==========================================
console.log("=== CREACIÓN DE USUARIOS VÍA FACTORY ===");
const admin = UsuarioFactory.crearUsuario('admin', 'Carlos Mendoza', '[email protected]');
const profe = UsuarioFactory.crearUsuario('docente', 'Valeria Torres', '[email protected]');
const alumno = UsuarioFactory.crearUsuario('estudiante', 'Mateo Silva', '[email protected]');
console.log(admin.obtenerPerfil());
console.log(profe.obtenerPerfil());
console.log(alumno.obtenerPerfil());
console.log("\n=== COMPROBACIÓN DE PERMISOS ===");
console.log("¿El alumno puede eliminar?:", alumno.tienePermiso('eliminar')); // false
console.log("¿El admin puede configurar el sistema?:", admin.tienePermiso('configurar_sistema')); // true
console.log("\n=== PRUEBA DE INMUTABILIDAD CON OBJECT.FREEZE ===");
// Intento de mutar la lista de permisos congelada:
try {
alumno.permisos.push('eliminar'); // Fallará porque el array está congelado
} catch (e) {
console.log("✔ Intento de inyectar permisos bloqueado por Object.freeze():", e.message);
}
console.log("Permisos del alumno intactos:", alumno.permisos);
Mini-Quiz de Retención
Comprueba tu comprensión antes de pasar a la siguiente lección¿Qué efecto produce ejecutar Object.freeze(objeto) sobre una estructura de datos en JavaScript?
¿Tienes dudas con este tema?
Sócrates AI puede darte analogías y explicarte este código paso a paso.🚀 ¿Quieres dominar Manual de Programación Orientada a Objetos en JavaScript (POO) y crear proyectos reales?
Aprende arquitectura limpia, desarrollo web moderno, buenas prácticas y despliegue en producción con nuestro Bootcamp Fullstack Developer con mentorías en vivo.
🏛️ Autoría y Propiedad Intelectual: Obra educativa original de David Amador para Kilopolis Academia (Solucionáticos), estructurada sobre las especificaciones y estándares abiertos del W3C, el estándar vivo de WHATWG y la documentación oficial de código abierto. © Todos los derechos reservados.