Cuantas veces has escrito codigo 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");
O talvez usaste un "switch" para lograr esto mismo.
Inmediatamente podemos ver un patron ahi: Metodo1, Metodo2 y Metodo3 todos tienen la misma estructura y se ejecutan cuando pasamos los valores Type1, Type2 y Type3. No seria bueno si pudieramos reducir ese codigo a una sola linea?
Eso es exactamente lo que los arreglos de metodos pueden hacer por ti, vamos a ver un ejemplo, antes de poderlos usar tenemos que prepararlos.
Como todos los metodos comparten la misma estructura, esto quiere decir que podemos usar un delegado para representar todos los metodos
delegate void AddStringDelegate(string someValue);
Ahora declaramos un arreglo de delegados:
AddStringDelegate[] addStringMethods;
tambien vamos a necesitar un tipo enum para accesar los metodos del arreglo:
enum StringType {
Type1,
Type2,
Type3,
Type4
}
Luego tenemos los metodos en si:
void AddStringType1(string someValue) {Finalmente, en el constructor de nuestra clase, podemos asignar los metodos al arreglo usando el delegado y de esta manera obtenemos nuestro arreglo de metodos:
OutputText(string.Format("String Type 1: {0}", someValue));
}
void AddStringType2(string someValue) {
OutputText(string.Format("String Type 2: {0}", someValue));
}
void AddStringType3(string someValue) {
OutputText(string.Format("String Type 3: {0}", someValue));
}
addStringMethods = new AddStringDelegate[3];
addStringMethods[(int)StringType.Type1] = new AddStringDelegate(AddStringType1);
addStringMethods[(int)StringType.Type2] = new AddStringDelegate(AddStringType2);
addStringMethods[(int)StringType.Type3] = new AddStringDelegate(AddStringType3);
Ya esta listo para ser usado, vamos a ver como se veria el codigo que presente al inicio, ahora usando nuestro arreglo:
public void AddString(string someValue, StringType stringType) {
addStringMethods[(int)stringType](someValue);
}
Como puedes ver, podemos accesar el metodo requerido pasando el tipo (y convirtiendolo a entero porque C# no nos deja hacerlo si no lo convertimos); nuestro codigo ahora se redujo a una simple linea, pasamos el enum stringType y este ejecuta el metodo correcto automaticamente.
El uso de esta tecnica por ahora se las dejo de tarea a ustedes, yo no recomendaria usar esta tecnica en una clase pequeña que creamos y tiramos constantemente, pero en algunos casos talvez aun asi podria ser util.
Yo creo que seria especialmente util si tuvieramos este tipo de patron (donde queremos ejecutar ciertos metodos dependiendo de ciertos values de enumeracion) dentro de un patron singleton, o donde la clase potencialmente podria vivir mucho mas, podrias hacer todo el trabajo de inicializar tu arreglo de metodos y asi poder reutilizarlos efectivamente.
Aqui esta todo el codigo para este ejemplo, en mi siguiente post les mostrare como podemos usar esta tecnica para implementar un tipo de factory pattern (patron de fabrica) o mas concretamente el simple factory pattern (patron de fabrica simple).
Precisamente hoy mismo acabo de usar este patron (que yo le llamo "simplified simple factory pattern") en mi proyecto actual, donde creo una instancia de la clase generadora y la reuso cada que necesito un objeto nuevo (dependiendo del tipo requerido)
class FileGeneratorBase {
delegate void AddStringDelegate(string someValue);
AddStringDelegate[] addStringMethods;
public FileGeneratorBase() {
addStringMethods = new AddStringDelegate[4];
addStringMethods[(int)StringType.Type1] = new AddStringDelegate(AddStringType1);
addStringMethods[(int)StringType.Type2] = new AddStringDelegate(AddStringType2);
addStringMethods[(int)StringType.Type3] = new AddStringDelegate(AddStringType3);
addStringMethods[(int)StringType.Type4] = new AddStringDelegate(AddStringType4);
}
public void AddString(string someValue, StringType stringType) {
addStringMethods[(int)stringType](someValue);
}
void AddStringType1(string someValue) {
OutputText(string.Format("String Type 1: {0}", someValue));
}
void AddStringType2(string someValue) {
OutputText(string.Format("String Type 2: {0}", someValue));
}
void AddStringType3(string someValue) {
OutputText(string.Format("String Type 3: {0}", someValue));
}
void AddStringType4(string someValue) {
OutputText(string.Format("String Type 4: {0}", someValue));
}
void OutputText(string someValue) {
Console.WriteLine(someValue);
}
}
class Program {
static void Main(string[] args) {
FileGeneratorBase fg = new FileGeneratorBase();
fg.AddString("some value", StringType.Type1);
fg.AddString("some other value", StringType.Type2);
fg.AddString("one last value", StringType.Type3);
fg.AddString("testing out of bounds", StringType.Type4);
Console.ReadLine();
}
}
Actualizado: Para incluir el tipo enum en la inicializacion de los metodos,
en lugar de 0..4 que tenia inicialmente, esto nos permitiria cambiar el orden
de los elementos de la enumeracion