Eric Evans y Martin Fowler fueron los responsables de esta tendencia llamada Fluent Interface. El objetivo de la misma no era otro que el de mejorar la legibilidad del código. Para saber cómo son y de qué forma podríamos crear nuestras propias interfaces veamos un sencillo ejemplo:
Supongamos que tenemos una clase que construye ordenadores con sus respectivas propiedades:
[sourcecode lang="csharp"]class Machine
{
public string Processor { get; set; }
public int RAM { get; set; }
}[/sourcecode]
Si quisiéramos crear un nuevo equipo y además inicializar sus componentes de la forma convencional sería algo parecido a esto:
[sourcecode lang="csharp"]var newMachine = new Machine {RAM = 6, Processor = "Intel i7 920"};[/sourcecode]
Si además esta clase Machine tuviera una serie de métodos encargados de realizar acciones como encender el ordenador, testearlo, apagarlo, etcétera ejecutaríamos cada uno de ellos invocando línea a línea los métodos declarados en dicha clase:
[sourcecode lang="csharp"]var newMachine = new Machine { RAM = 6, Processor = "Intel i7 920" };
newMachine.TurnOn();
newMachine.Test();
newMachine.TurnOff();[/sourcecode]
¿Qué nos ofrece Fluent Interface?
[sourcecode lang="csharp"]new Computer()
.AddProcessor("Intel i7 920")
.AddRAM(6)
.TurnOn()
.Test()
.TurnOff();[/sourcecode]
Si nos damos cuenta se trata de una línea de código abarcando todas las funciones que nos interesan de una clase de tipo Machine, encapsulada dentro de Computer. ¿Cómo creamos este encapsulamiento?
En primer lugar vamos a definir una interfaz que establezca los métodos disponibles y obligatorios de implementar:
[sourcecode lang="csharp"]namespace FluentInterface
{
interface IComputer
{
IComputer TurnOn();
IComputer TurnOff();
IComputer Test();
IComputer AddRAM(int GB);
IComputer AddProcessor(string model);
}
}[/sourcecode]
Lo primero que nos puede llamar la atención es que cada uno de los métodos deberá retornar el tipo IComputer, es decir, debería devolver una clase que implemente esta interfaz que estamos declarando o dicho de otra forma: Deberá devolverse a sí mismo. ¿Qué conseguimos con ello? Devolver el contexto (valores de las variables) en cada acción que vayamos invocando para poder ser utilizado en la siguiente llamada. Como implementación válida a esta interfaz tendríamos lo siguiente:
[sourcecode lang="csharp"]using System;
namespace FluentInterface
{
class Computer : IComputer
{
private readonly IMachine _machine;
public Computer()
{
_machine = new Machine();
}
public IComputer TurnOn()
{
_machine.Status = "On";
Console.WriteLine("Your computer is {0}", _machine.Status);
return this;
}
public IComputer TurnOff()
{
_machine.Status = "Off";
Console.WriteLine("Your computer is {0}", _machine.Status);
return this;
}
public IComputer Test()
{
Console.WriteLine("Your computer is {0}", _machine.Status);
return this;
}
public IComputer AddRAM(int GB)
{
_machine.RAM = GB;
Console.WriteLine("{0} GB RAM added. Do you think its enough?", _machine.RAM);
return this;
}
public IComputer AddProcessor(string model)
{
Console.WriteLine("{0} processor added.", _machine.Processor);
_machine.Processor = model;
return this;
}
}
}[/sourcecode]
En cada uno de los métodos realizaremos las operaciones necesarias y finalmente retornaremos this, es decir, la instancia de la clase que implementa IComputer para poder continuar operando con ella de una manera fluida. Gracias a este estilo de programación conseguiremos un código más legible y atractivo para el desarrollador :)
¡Saludos!
No hay comentarios:
Publicar un comentario