Cascade-Lambda pattern

Es momento de hacer más interesante el patrón anterior. Antes que nada recordemos cual fue el resultado final en ese momento:

new EmailManager()
    .Client("client")
    .From("from@sebys.com.ar")
    .To("to@sebys.com.ar")
    .Subject("Envio email")
    .Body("Este es el contenido del e-mail")
    .Send();

Como podrán notar, el método Send() es el que realiza la “acción final” en todas las instancias de EmailManager. Esto nos permite deducir dos cosas, la primera es que toda instancia de EmailManager “finaliza” cuando realizamos el envío de correo y la segunda es que implícitamente estamos diciendo que para realizar un nuevo envío de correo necesitamos crear una nueva instancia. Aunque el comportamiento es bastante lógico, nuestra API no es explicitamente clara en su comportamiento.

Para hacer explicito este comportamiento, podemos hacer uso de las expresiones lambda.

Para trabajar con expresiones lambda vamos a convertir el método Send() es un método estático y cambiar su firma para que acepte un delegado Action<T>. Este delegado debe tomar como parámetro una instancia de EmailManager. Por último vamos a invocar la acción dentro del método, previo a realizar el envío propiamente dicho:

public static void Send(Action action)
{
    action(new EmailManager());
    Console.WriteLine("Enviar correo...");
}

Ahora veamos como cambia la forma de invocar a EmailManager:

static void Main(string[] args)
{
    EmailManager.Send((mail) => mail.Client("client")
                                   .From("from@sebys.com.ar")
                                   .To("to@sebys.com.ar")
                                   .Subject("Envio email")
                                   .Body("Este es el contenido"));
}

Con esto logramos eliminar toda confusión acerca de como debe realizarse el envió del e-mail, ya que lo que el método Send() establece claramente donde debe “construirse” el correo y que puede enviarse una única vez por instancia.

¡Espero que les sea de utilidad!

Anuncios

Abstract Factory Pattern

Después de una larga ausencia por motivos personales, vuelvo al ruedo. En esta oportunidad voy a escribir una sería de artículos volviendo a unos de los temas que más me interesan en programación que son los patrones de diseño. Para esta serie de post – y los ejemplos – me base en el artículo “Moving forward with .NET – Design Patterns” de la edición número 16 de la revista DNCMag.

Antes de arrancar con este patrón, veamos algunas definiciones (Wikipedia):

1. A factory creates objects.

2. The abstract factory pattern provides a way to encapsulate a group of individual factories that have a common theme without specifying their concrete classes.

La interpretación e implementación de este patrón puede ser variable. Una variación del mismo puede ser el patrón Factory, sin embargo si nos basamos en la definición anterior, este patrón lo que busca es que alguien se encargue crear instancias de objectos sin necesidad de especificar la clase concreta.

Veamos un ejemplo – aplicación de consola con C# – para que nos ayude a comprender mejor este patrón:

public class Book
{
    public string Title { get; set; }
   
    public int Pages { get; set; }
        
    public override string ToString()
    {
        return string.Format("Book {0} - {1}", Title, Pages);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(CreateInstance("AbstractFactoryPattern.Book", new Dictionary<string, object>() {
            {"Title", "Gulliver’s Travels"},
            {"Pages", 10},
        }));
    }

    private static object CreateInstance(string className, Dictionary<string, object> values)
    {
        Type type = Type.GetType(className);
        object instance = Activator.CreateInstance(type);

        foreach (var entry in values)
        {
            type.GetProperty(entry.Key).
            SetValue(instance, entry.
            Value, null);
        }
        return instance;
    }
}

En este sencillo ejemplo, la generación de instancias se delega al método CreateIntances(). Al momento de invocarlo hay que especificar como parámetros el nombre de la clase que queremos instanciar y los valores de sus propiedades por medio de un diccionario (key: nombre propiedad, value: valor).

Si bien pueden pensar que se trata solo de un método que crea instancias, este patrón puede ser muy poderoso cuando necesitamos generar nuevas instancias dinámicamente y en tiempo de ejecución a partir de las entrada de datos de un usuario. Además este patrón juega un papel clave en la inyección de dependencias (en el enlace hay mas detalle al respecto).

Si bien el ejemplo anterior es una demostración muy puntual de este patrón, existen otras formas de implementación como la del siguiente ejemplo.

Espero que les sea de utilidad!