Cómo mejorar los condicionales con objetos y funciones


Antes de empezar

Los condicionales son fundamentales en programación, pero a menudo generan código difícil de mantener. Te voy a mostrar cómo transformar largas cadenas de if/else y switch en soluciones más elegantes usando objetos y funciones.

Problemáticas de los condicionales tradicionales

1. Cadenas largas de if/else

function obtenerSaludo(idioma) {
  if (idioma === 'es') {
    return '¡Hola!';
  } else if (idioma === 'en') {
    return 'Hello!';
  } else if (idioma === 'fr') {
    return 'Salut!';
  } else if (idioma === 'it') {
    return 'Ciao!';
  } else if (idioma === 'de') {
    return 'Hallo!';
  } else {
    return 'Hi!';
  }
}

Problemas:

  • Código repetitivo y poco verboso
  • Difícil de mantener cuando crece
  • Nos saltamos el principio Open/Closed

2. Switch statements largos

function calcularDescuento(tipoCliente) {
  switch (tipoCliente) {
    case 'premium':
      return 0.20;
    case 'gold':
      return 0.15;
    case 'silver':
      return 0.10;
    case 'bronze':
      return 0.05;
    default:
      return 0;
  }
}

Problemas:

  • Fácil olvidar el break
  • No escalable
  • Dificultad para testing individual

Solución 1: Objetos como mapas

Ejemplo básico: Saludos

const saludos = {
  es: '¡Hola!',
  en: 'Hello!',
  fr: 'Salut!',
  it: 'Ciao!',
  de: 'Hallo!'
};

function obtenerSaludo(idioma) {
  return saludos[idioma] || 'Hi!';
}

// Uso
console.log(obtenerSaludo('es')); // ¡Hola!

Ejemplo avanzado: Piedra, Papel o Tijera

const gameRules = {
  piedra: 'tijera',    // piedra gana a tijera
  papel: 'piedra',     // papel gana a piedra
  tijera: 'papel'      // tijera gana a papel
};

function determinarGanador(jugador, maquina) {
  if (jugador === maquina) return 'Empate';
  return gameRules[jugador] === maquina ? 'Ganaste' : 'Perdiste';
}

// Uso
console.log(determinarGanador('piedra', 'tijera')); // Ganaste
console.log(determinarGanador('papel', 'piedra'));  // Ganaste

Solución 2: Objetos con funciones

Calculadora con operaciones

const operaciones = {
  suma: (a, b) => a + b,
  resta: (a, b) => a - b,
  multiplicacion: (a, b) => a * b,
  division: (a, b) => b !== 0 ? a / b : 'Error: División por cero'
};

function calcular(operacion, a, b) {
  const operador = operaciones[operacion];
  return operador ? operador(a, b) : 'Operación no válida';
}

// Uso
console.log(calcular('suma', 5, 3));         // 8
console.log(calcular('division', 10, 2));    // 5

Sistema de validaciones

const validadores = {
  email: (valor) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(valor),
  telefono: (valor) => /^\d{9}$/.test(valor),
  password: (valor) => valor.length >= 8,
  nombre: (valor) => valor.length >= 2 && /^[a-zA-ZáéíóúÑñ\s]+$/.test(valor)
};

function validarCampo(tipo, valor) {
  const validador = validadores[tipo];
  return validador ? validador(valor) : false;
}

// Uso
console.log(validarCampo('email', 'test@email.com')); // true
console.log(validarCampo('telefono', '123456789'));   // true

Solución 3: Map para casos complejos

Gestión de estados

const estadosUsuario = new Map([
  ['activo', { color: 'green', mensaje: 'Usuario activo', acciones: ['editar', 'eliminar'] }],
  ['inactivo', { color: 'gray', mensaje: 'Usuario inactivo', acciones: ['activar'] }],
  ['bloqueado', { color: 'red', mensaje: 'Usuario bloqueado', acciones: ['desbloquear'] }],
  ['pendiente', { color: 'yellow', mensaje: 'Pendiente de verificación', acciones: ['verificar'] }]
]);

function obtenerInfoUsuario(estado) {
  return estadosUsuario.get(estado) || { 
    color: 'black', 
    mensaje: 'Estado desconocido', 
    acciones: [] 
  };
}

// Uso
const info = obtenerInfoUsuario('activo');
console.log(info.mensaje); // Usuario activo
console.log(info.acciones); // ['editar', 'eliminar']

Comparación de rendimiento

Método tradicional (lento)

function obtenerPrecio(producto) {
  if (producto === 'laptop') return 1200;
  if (producto === 'mouse') return 25;
  if (producto === 'teclado') return 80;
  if (producto === 'monitor') return 300;
  if (producto === 'altavoces') return 150;
  // ... más productos
  return 0;
}

Método optimizado (rápido)

const precios = {
  laptop: 1200,
  mouse: 25,
  teclado: 80,
  monitor: 300,
  altavoces: 150
};

const obtenerPrecio = (producto) => precios[producto] || 0;

Ternarios: cuándo usarlos

Casos apropiados

// ✅ Bueno: asignación simple
const mensaje = usuario.activo ? 'Bienvenido' : 'Cuenta desactivada';

// ✅ Bueno: clases CSS
const className = `btn ${esImportante ? 'btn-primary' : 'btn-secondary'}`;

Casos a evitar

// ❌ Malo: ternarios anidados
const resultado = condicion1 ? 
  (condicion2 ? 'caso1' : 'caso2') : 
  (condicion3 ? 'caso3' : 'caso4');

// ✅ Mejor: objeto
const casos = {
  [condicion1 && condicion2]: 'caso1',
  [condicion1 && !condicion2]: 'caso2',
  [!condicion1 && condicion3]: 'caso3'
};
const resultado = Object.entries(casos).find(([key]) => key)?.[1] || 'caso4';

Sistema de notificaciones

const tiposNotificacion = {
  success: {
    icono: '✅',
    color: '#4CAF50',
    duracion: 3000,
    sound: 'success.mp3'
  },
  error: {
    icono: '❌',
    color: '#F44336',
    duracion: 5000,
    sound: 'error.mp3'
  },
  warning: {
    icono: '⚠️',
    color: '#FF9800',
    duracion: 4000,
    sound: 'warning.mp3'
  },
  info: {
    icono: 'ℹ️',
    color: '#2196F3',
    duracion: 3000,
    sound: 'info.mp3'
  }
};

function mostrarNotificacion(tipo, mensaje) {
  const config = tiposNotificacion[tipo];
  if (!config) {
    console.error('Tipo de notificación no válido');
    return;
  }
  
  // Crear y mostrar notificación
  const notificacion = {
    mensaje,
    ...config,
    timestamp: Date.now()
  };
  
  console.log(`${config.icono} ${mensaje}`);
  // Aquí iría la lógica de UI real
  
  return notificación;
}

Beneficios de estas técnicas

🚀 Rendimiento: Acceso O(1) vs O(n) en if/else largos

🧹 Mantenibilidad: Código más limpio y fácil de modificar

📈 Escalabilidad: Agregar nuevos casos es trivial

🧪 Testabilidad: Cada función puede testearse independientemente

🔒 Inmutabilidad: Los objetos pueden ser congelados para evitar modificaciones

const configInmutable = Object.freeze({
  development: { debug: true, apiUrl: 'localhost:3000' },
  production: { debug: false, apiUrl: 'api.miapp.com' }
});

Estas técnicas no solo mejoran la legibilidad del código, sino que también lo hacen más eficiente y mantenible. La próxima vez que veas una larga cadena de if/else, recuerda que probablemente hay una forma más elegante de resolverlo.


Usamos cookies para mejorar tu experiencia. ¿Aceptas las cookies de análisis?