Código repetido? Func<T> al rescate

Un problema muy común que nos podemos llegar a topar al desarrollar, es encontrarnos con métodos sumamente parecidos. En ellos podemos notar que su comportamiento son muy similares y que podrían diferenciarse por muy poco. 
Paar graficar un poco mejor las cosas, imaginemos un caso muy sencillo en el tenemos un Wrapper de un WebService:



namespace EjemploSimple
{
 public class WrapperMyWebService
 {
  private MyWebService webService;

  public WrapperMyWebService(MyWebService webService)
  {
   this.webService = webService;
  }

  public string GetWebServiceStatus()
  {
   return this.webService.GetStatus();
  }

  public string GetSomeValue( int key )
  {
   return this.webService.GetSomeValue( key );
  }
 }
}

Hasta aquí, la clase tiene dos métodos con comportamientos diferentes. Cada uno posee una única línea de código que se encarga de llamar a métodos diferentes del objeto al cual envuelven. Pero qué sucede si se le cambia el comportamiento a ambos métodos:


namespace EjemploSimple
{
 public class WrapperMyWebService
 {
  private MyWebService webService;

  public WrapperMyWebService(MyWebService webService)
  {
   this.webService = webService;
  }

  public string GetWebServiceStatus()
  {
   string ret = "";
   try
   {
    ret = this.webService.GetStatus();   
   }
   catch( Exception e )
   {
    ret = string.Concat( "ERROR: ",  e.Message );
   }

   return ret;
  }

  public string GetSomeValue( int key )
  {
   string ret = "";
   try
   {
    ret = this.webService.GetSomeValue( key );   
   }
   catch( Exception e )
   {
    ret = string.Concat( "ERROR: ",  e.Message );
   }

   return ret;
  }
 }
}

En esta nueva versión de la clase, podemos notar que ahora la mayor parte del código está repetido. En ambos casos se desea atrapar una excepción y en ambos casos se desea devolver el mensaje de error. Imaginemos ahora que debemos agregar más métodos con el mismo comportamiento y que luego, ese mismo comportamiento quiere ser modificado para todos los métodos. Se debe escribir esa modificación tantas veces como métodos con el mismo comportamiento hubiera.
Aquí es donde viene en nuestra ayuda "Generics". Generics posee varias herramientas. Una de ellas se puede aplicar para solucionar este problema: Func<T>.
Primero y principal, debemos determinar la lógica repetida:


  public string MethodName()
  {
   string ret = "";
   try
   {
    //Invoke Web Service method.
   }
   catch( Exception e )
   {
    ret = string.Concat( "ERROR: ",  e.Message );
   }

   return ret;
  }

Como podemos apreciar, sólo la invocación al método del web service es lo que diferencia a ambos métodos. Func<T> nos permite poder pasar como argumento a otro método un "puntero" a una función para que se invocada. Para nuestro ejemplo, el método genérico quedaría así:


namespace EjemploSimple
{
 public class WrapperMyWebService
 {
  private MyWebService webService;

  public WrapperMyWebService(MyWebService webService)
  {
   this.webService = webService;
  }

  public string GetWebServiceStatus()
  {
   return this.GenericGetter( () => this.webService.GetStatus() );
  }

  public string GetSomeValue( int key )
  {
   return this.GenericGetter( () => this.webService.GetSomeValue( key ) );
  }

  public string GenericGetter( Func<T> fetch )
  {
   string ret = "";
   try
   {
    ret = fetch;
   }
   catch( Exception e )
   {
    ret = string.Concat( "ERROR: ",  e.Message );
   }

   return ret;
  }
 }
}

En este último ejemplo, podemos notar que el método que poseía el comportamiento repetido queda escrito una sola vez y los métodos que tenían dicho comportamiento, pasan a ejecutar esta nueva función pasándole como argumento el puntero a la función del Web Service que se desea invocar.

0 comentarios:

Publicar un comentario

Muchas gracias por leer el post y comentarlo.

 
Copyright 2009 Programación SOLIDa
BloggerTheme by BloggerThemes | Design by 9thsphere