Saturday, September 09, 2006

Simple factory pattern hecho mas simple

El "Simple Factory pattern" (algo asi como patron de creacion simple) regresa una instancia de varias posibles, dependiendo de los parametros que le pasemos a este.

La semana pasada hablaba de una tecnica que te permite reducir (y reusar efectivamente) tu codigo, cuando tienes un patron de 2 o mas valores, donde por cada valor quieres ejecutar un metodo diferente de la misma estructura, algo mas o menos asi:

if (someValue == SomeEnum.Type1)
  Method1("value 1");
else if (someValue == SomeEnum.Type2)
  Method2("value 2");
else if (someValue == SomeEnum.Type2)
  Method3("value 3");

Mientras que este metodo es valioso por si mismo, hay un patron donde se acomoda perfectamente, este patron es el "Simple factory pattern"; vamos a ver un ejemplo usando unos reportes ficticios

Supongamos que tenemos una clase base, y dos implementaciones de esta:

abstract class BaseReport {
public BaseReport() {
Console.WriteLine("Base Report Created");
}
public abstract void Execute();
}
class Report1 : BaseReport {
public Report1():base() {
Console.WriteLine("Report1 created");
}
public override void Execute() {
Console.WriteLine("Report1");
}
}
class Report2 : BaseReport {
public Report2():base() {
Console.WriteLine("Report2 created");
}
public override void Execute() {
Console.WriteLine("Report2");
}
}

enum ReportType {
Report1,
Report2
}

Para usar arreglos de metodos, declaramos un delegado que servira para crear las instancias de los reportes:

delegate BaseReport ReportCreatorDelegate();

Luego tenemos la clase implementadora que contiene:



  • Un arreglo de metodos
  • Un metodo para crear cada reporte
  • El metodo para ejecutar el reporte que necesitemos, dependiendo de los parametros
class ReportGenerator {
static BaseReport CreateReport1() {
return new Report1();
}
static BaseReport CreateReport2() {
return new Report2();
}
static ReportCreatorDelegate[] reports;
static ReportGenerator() {
reports = new ReportCreatorDelegate[2];
reports[0] = new ReportCreatorDelegate(CreateReport1);
reports[1] = new ReportCreatorDelegate(CreateReport2);
}
public static BaseReport Execute(ReportType reportType) {
return reports[(int)reportType]();
}
}

Como pueden ver el codigo ese simple, hay una simple linea que ejecuta el reporte que necesitamos, dependiendo del enum que le pasemos, aqui esta un ejemplo del uso del codigo:

BaseReport report1 = ReportGenerator.Execute(ReportType.Report1);
report1.Execute();

BaseReport report2 = ReportGenerator.Execute(ReportType.Report2);
report2.Execute();
Console.ReadLine();

Algo importante que notar, aqui en este ejemplo yo estoy pasando el enum para el reporte que quiero ejecutar, alguien me dijo en mi otro blog (en ingles) que no tenia caso tener el patron, que ahi directamente podia yo crear la instancia; en este caso especificamente si podria ser asi, pero el valor del enum para el reporte que queremos ejecutar podria venir de un drop down list, de la configuracion, de una llamada a un web service, etc


Este ejemplo particular es realmente liviano y funciona muy bien para implementar este paterno, pero tiene la limitacion de que solo funciona para valores que pueden ser convertidos a tipos numericos enteros


Ayende y Steven correctamente mencionaron en mi otro blog que la misma tecnica puede ser implementada usando diccionarios, esto nos permitiria usar otros tipos de datos como el indice de nuestra coleccion de metodos


En mis siguientes posts hablare de como implementar esa tecnica de usar diccionarios de metodos, realmente es muy similar a esta


Por ahora pueden encontrar todo el codigo para este y el ejemplo previo aqui

No comments: