Si los 'if' fueran ineficaces ni siquiera formarían parte de la lógica... pero es que la lógica se basa exclusivamernte en los condicinales... a nivel 'atómico', son puertas AND, OR y XOR... lo que al final configuran los 'if'... cuando hacemos un if, estamos haciendo una comparación que a nivel de diseño, es una resta, y cuyo resultado arroja uno de 3 valores <0, 0 ó >0. Como resultado uno o más bits del registro de estado del procesador (en los x86), se activa y luego es cuando el programador puede 'test'ear el resultado.
Gran parte de la lógica digital descansa precisamente en esto... y en los saltos (al caso condicionados por el resultado de la comparación).
....
Esto no quiere decir que lo que te han señalado sobre el uso y abuso de 'IF', como que es mala programación no sea correcto, siempre que se entienda sin ambigüedad a que se quiere referir..., y parta ello te expongo claramente el ejemplo de 'no usar + ifs' de los necesarios...
Por ejemplo, en el caso de calcular fechas... dado que es complejo, verificar en concreto si un día, de un mes, de un año cae por ejemplo es tal o cual día ó si es válido (existe dicho día para dicho mes), exige usando IFs, muchas comprobaciones... entonces al caso es que es preferible resolverlo de forma más arítmetica que lógica...
En otras ocasones es haciendo uso de las operaciones lógicas más elementales: AND, OR, XOR qwue al fin y al cabo, bien entendidos son otra forma de condicionales.
Lo que se hace en general es calcular, y al final basta uno solo o dos condiconales.
Una foma sencilla de usar 'If's y no sobrecargar con cada llamada es entender que todos los meses tienen un nínimo de 28 días, luego no es preciso hacer un cácluclo total y abusivo con cada fecha que se llame...
Por claridad creamos una estructura que comprenda los datos precisos.
Estructura Fecha
byte día
byte mes
entero año
fin estructura
También por claridad, no se consideran (en la función) los casos en que mes, día o año estén fuera de rango...
Si ((f.año > x) y (f.año < y)) //x,y representan un límite impuesto para el año....
Si (f.mes > 0) y (f.Mes < 12) // mes va en el rango 1-12, descartar cualquier otra posibilidad (aunque podría ir en el rango 0-11).
Si (f.dia > 0) y (f.dia < 32) // se supone que día está en el rango 1-31
buleano = Funcion ValidarFecha(fecha f)
Si (f.dia <= 28)
devolver TRUE
Sino
devolver ValidarFechaAFondo(f)
Fin si
Fin funcion
Aquí es cuando nos meteríamos en verificar si el día es 29, 30 ó 31 en base al mes y en caso de ser febrero el mes, en si es bisiesto.
buleano = Funcion ValidarFechaAFondo(fecha f)
byte mes = f.mes
Si (mes = 2) // febrero
Si (f.Dia <30)
Si AñoEsbisiesto(f.año)
devolver TRUE
fin si
fin si
Sino
// el 'ó', es también un condicional... así esta línea tiene 4 condicionales.
Si (mes = 4) ó (mes = 6) ó (mes = 9) ó (mes = 11)
Si (f.dia < 31)
devolver TRUE
Fin si
Sino //enero, marzo, mayo, julio, agosto, octubre y diciembre tienen 31 días.
devolver TRUE
Fin si
Fin si
devolver FALSE
Fin Funcion
Por ejemplo: si queremos hacer algo basado en si un mes tiene 30, 31, 28, ó 29 días... sería relativamente sencillo, crear un array... que aunque largo, contuviera ya la solución, así se ahorrarían muchísimos 'IF's, y solo sería preciso una comprobación posterior para el caso de febrero cuando se señale el día 29 y no para 30 y 31
Nota ahora como el siguiente código ahorra mucho código a cambio de ocupar más memoria, con un array...
// mes , día
Array de bytes DiaMesValido(0 a 12, 0 a 2) // el mes 0, no se usa...
Funcion RellenarArrayValido
// Enero
DiaMesValido(1,0) = 1 // día 29
DiaMesValido(1,1) = 1 // día 30
DiaMesValido(1,2) = 1 // día 31
// Marzo
DiaMesValido(3,0) = 1 // día 29
DiaMesValido(3,1) = 1 // día 30
DiaMesValido(3,2) = 1 // día 31
// Mayo
DiaMesValido(5,0) = 1 // día 29
DiaMesValido(5,1) = 1 // día 30
DiaMesValido(5,2) = 1 // día 31
// Julio
DiaMesValido(7,0) = 1 // día 29
DiaMesValido(7,1) = 1 // día 30
DiaMesValido(7,2) = 1 // día 31
// Agosto
DiaMesValido(8,0) = 1 // día 29
DiaMesValido(8,1) = 1 // día 30
DiaMesValido(8,2) = 1 // día 31
// Octubre
DiaMesValido(10,0) = 1 // día 29
DiaMesValido(10,1) = 1 // día 30
DiaMesValido(10,2) = 1 // día 31
// Diciembre
DiaMesValido(12,0) = 1 // día 29
DiaMesValido(12,1) = 1 // día 30
DiaMesValido(12,2) = 1 // día 31
// Mes de 29 días: Calcular bisiesto
// Febrero
DiaMesValido(2,0) = 255 // día 29
DiaMesValido(2,1) = 0 // día 30
DiaMesValido(2,2) = 0 // día 31
/ Meses de 30 días: Abril, Junio, Septiembre y Noviembre
// Abril
DiaMesValido(4,0) = 1 // día 29
DiaMesValido(4,1) = 1 // día 30
DiaMesValido(4,2) = 0 // día 31
// Junio
DiaMesValido(6,0) = 1 // día 29
DiaMesValido(6,1) = 1 // día 30
DiaMesValido(6,2) = 0 // día 31
// Septiembre
DiaMesValido(9,0) = 1 // día 29
DiaMesValido(9,1) = 1 // día 30
DiaMesValido(9,2) = 0 // día 31
// Noviembre
DiaMesValido(11,0) = 1 // día 29
DiaMesValido(11,1) = 1 // día 30
DiaMesValido(11,2) = 0 // día 31
Fin funcion
// Al inicializar el componente se crea el array (estático) una única vez.
funcion Inicializar
llamada a la funcion RellenarArrayValido
fin funcion
La función de validación (es la misma que la previa):
buleano = Funcion ValidarFecha(fecha f)
Si (f.dia <= 28)
devolver TRUE
Sino
devolver ValidarFechaAFondo(f)
Fin si
Fin funcion
Y finalmente la función de validación 'a fondo' ahora queda así:
buleano = Funcion ValidarFechaAFondo(fecha f)
byte resultado
resultado = DiaMesValido(f.mes, f.dia - 29)
Si (resultado = 1)
devolver TRUE
Si (resultado = 255) // caso de febrero, día 29...
Si AñoEsbisiesto(f.año)
devolver TRUE
Fin si
Fin si
devolver FALSE
fin funcion
Incluso si comparas la primera función (que yo expongo) con tú código, ésta es mucho más óptima, sigue sin necesitar entrar en consideraciones extras si el día es inferior a 29, ya que todos los meses tienen esos días... pero en la 2ª función que expongo...
Como se puede ver, se ha limitado mucho la cantidad de los 'If's usados. Hay otras opciones igualmente aceptables, pero la idea simplemente es la demostrar que el número de condicionales puede ser limitado de diferentes maneras, en el ejemplo mediante el uso de un array pre-configurado con las soluciones...
Ante una miríada de llamadas, se puede ver que solo se va a calcular si el año es bisiesto, tan solo cuando el mes introducido es febrero y el día 29 (tampoco si se indica día 30, ni 31 para febrero), y no con cada fecha que se recibe....
La función AñoEsBisiesto... queda a tu esfuerzo, baste saber que cada 4 años es bisiesto, y que los acabados en 00, no lo son, pero cada 400 años, el que acabe enn 00 si lo es, etc... posiblemente en wikipedia esté bien explicado, si lo precisas...
Otros casos para evitar IFs conllevan usar aritmética, o solucionando casos con AND, OR y XOR (pueden testear varios bits a la vez, en vez de verificar cada caso con un 'if suelto').