Guerra abierta al switch… case
Me estare volviendo paranoico… pero cada vez que veo un switch… case en un codigo C# (O Select… Case en Visual Basic.NET) me entra una especie de sarpullido que no puedo evitar.
Supongamos que tenemos una enumeracion y queremos presentar un texto dependiendo de esa enumeracion:
public enum eTipoMoneda
{
eDolar = 0,
ePeseta = 1,
eEuro = 2
}
public string DescripcionMoneda (eTipoMoneda tipo)
{
switch(tipo)
{
case eDolar:
return “Dolar”;
case ePeseta:
return “Peseta”;
case eEuro:
return “Euro”;
}
}
Algo muy simple, verdad… y bastante utilizado, por cierto. Bien, supongamos que montamos un software complejísimo en base a un sistema multimoneda con esta enumeracion de tipos y, no solo eso, sino que realizamos diferentes operaciones dependiendo de cada moneda: Implementariamos un select… case por cada operacion para diferenciarlas. Puede llegar un momento en el que el código sea totalmente insostenible.
Hay una regla básica, si hay un sitio donde aparecen un select con varios cases, es hora de implementar un interface. Como se haría? Utilizando el ejemplo anterior:
public interface ITipoMoneda
{
string Nombre{get;}
eTipoMoneda TipoMoneda {get;}
}
Podriamos implementar una clase para cada tipo de la siguiente manera:
public class CDolar, ITipoMoneda
{
public Nombre
{
get{ return “Dolar”;}
}
public eTipoMoneda
{
get { return eTipoMoneda.eDolar; }
}
}
public class CPeseta, ITipoMoneda
{
public Nombre
{
get{ return “Peseta”;}
}
public eTipoMoneda
{
get { return eTipoMoneda.ePeseta; }
}
}
Y tambien con el euro. He implementado la propiedad eTipoMoneda, para mantener un nexo de union con respecto al primer ejemplo, aunque en C# seria equivalente a: typeof() o GetType() en Visual Basic.NET.
Podriamos crear un contenedor estático que devuelva una lista con los tipos de monedas:
IList<ITipoMoneda> objLista = new List<ITipoMoneda>();
objLista.Add(new CDolar);
objLista.Add(new CPeseta);
Ahora si queremos mostrar las monedas de las que da soporte nuestro programa:
foreach(ITipoMoneda moneda in objLista)
Consele.WriteLine ( moneda.Nombre );
Seria fácil dar soporte a una nueva moneda en el programa…. verdad??
Tambien podríamos implementar fácilmente funcionalidad específica:
public interface ITipoMoneda
{
string Nombre{get;}
eTipoMoneda TipoMoneda {get;}
double FactorConversion {get;}
}
Entonces, una conversion entre monedas sería algo así:
public decimal ConvertirMonedas (ITipoMoneda objMonedaInicial, ITipoMoneda objMonedaFinal, decimal cantidad)
{
return (cantidad * objMonedaInicial.FactorConversion) / objMonedaFinal.FactorConversion;
}
Pensad en la cantidad de switch… cases que nos hemos comido con esta implementación. Pensad en lo fácil que es implementar nuevas monedas y, fijaros que esta última función siempre funcionará aún añadiendo nuevas monedas al sistema. Para dotar a estas clases de funcionalidad más específica vienen en nuestra ayuda los delegados, potenciados en .NET 2.0 con los objetos Action y Predicate…. bueno, ya hablaré más de ellos en otro post.
Por todo esto cuando veo un switch…case siempre pienso que seguramente haya una mejor manera de implementar el código… y, efectivamente, siempre la hay.
[…] Esto viene de un post que puse hace unos dias confesando mi odio a los multiples switch. […]