lunes, 14 de julio de 2014

[Patrones] Implementando patrón fachada - Facade pattern en C#

El patrón fachada nos permite disminuir la complejidad de un sistema, a través de la división de este en subsistemas, y adicional permite reducir la dependencia de un cliente con respecto a determinado componente. es decir, si tenemos una cantidad de operaciones que suelen ser complicadas, por ejemplo para hacer algo con un "Empleado", podríamos crear una fachada de empleado que nos permita consumir estas operaciones de una forma más simple y adicional centralice el acceso a estas operaciones, de esta forma cualquier cliente podría realizarlas sin tener que entrar en detalle de las operaciones complejas correspondientes a "Empleado" y además no tendría una dependencia directa con las implementaciones concretas de "Empleado" si no con la fachada, de modo que si algo cambia en estas implementaciones concretas, basta con modificar la fachada y los demás clientes no se darían por enterados.

Ahora veamos cómo es la estructura de este patrón y analicémoslo un poco antes de implementarlo en C#:

Imagen tomada de Wikipedia de (http://es.wikipedia.org/wiki/Facade_(patr%C3%B3n_de_dise%C3%B1o))

Como vemos en el diagrama, tenemos tres módulos A, B y C, los cuales tienen responsabilidades diferentes y estos interactúan entre sí para completar algunas de sus operaciones, y también vemos que el componente facade o fachada, usa estos tres módulos para exponer una funcionalidad que los involucra, quiere decir que un cliente que es otro componente que no vemos en el diagrama, accede a la fachada y no lo hace directamente a cada uno de los tres módulos que tenemos. Entonces la fachada es la encargada de operar con la complejidad que pueda tener cada uno de estos módulos y lo expone de una manera mucho más sencilla y entendible a un cliente que pueda necesitarlo, adicional la fachada nos permite desacoplar nuestros clientes de implementaciones concretas como las que tenemos en cada módulo, y de cambiar alguno de ellos, el cambio afectaría solo a la fachada y nuestros clientes no se darían cuenta de ello.

Ahora que conocemos el propósito de este patrón y sabemos cuál es su estructura, vamos a ver cómo es su implementación en Microsoft .Net usando C#, para esto nos vamos a plantear el siguiente escenario de aplicación:

En un sistema tenemos tres módulos que son, Nómina, Incentivos y Subsidios. Dichos módulos realizan operaciones que pueden ser complejas y críticas para un negocio, ya que operan en diferentes frentes relacionados con los empleados de una compañía, sin embargo, existen varias aplicaciones y existirán muchas más que necesiten usar funcionalidades de estos módulos y estas deben lograrlo de una manera sencilla y fácil de usar, sin tener que entrar en detalle de cada una de las reglas de negocio de cada módulo.

Para esto vamos a crear una solución en Visual Studio con los siguientes proyectos, que explicaré a continuación:


Los proyectos Beneficios, Incentivos y Nomina, son los tres módulos que tenemos en nuestra aplicación y son los que corresponden en el diagrama a ModuleA, ModuleB y ModuleC respectivamente, y es allí donde tenemos bastantes reglas de negocio y operaciones complejas, que queremos exponer de una forma mucho más simple.

El en proyecto Domino se encuentran nuestras entidades de dominio, es decir las entidades que son relevantes para el negocio, y las cuales transportaremos entre los diferentes proyecto para hablar en un mismo término de negocio, adicional estas entidades podrían estar mapeadas a nuestra base de datos por ejemplo, una de estas entidades es la entidad Empleado.

En el proyecto de fachada para nuestro ejemplo tenemos una sola clase llamada EmpleadoFacade la cual recibe ese nombre para efectos de este ejemplo, y es quien realiza el llamado a nuestros tres módulos nombrados anteriormente.

Y por último tenemos el proyecto ClienteFacturacion que es una aplicación dedicada al área de facturación, y que requiere el uso de las operaciones complejas de cada empleado, y como esta aplicación pueden existir muchas más que la necesiten, por esto consume todas las operaciones a través de la fachada.

Ahora veamos cómo es la implementación de cada uno de estos componentes:

Módulo de Nómina:

    public class Nomina
    {
        public double ObtenerSalarioEmpleado(string idEmpleado)
        {
            // Simulamos los empleados de la compañía
            var empleados = new List<Empleado>()
            {
                new Empleado() {Id = "1", Nombre = "Empleado 1", Salario = 1500000},
                new Empleado() {Id = "2", Nombre = "Empleado 2", Salario = 2000000},
                new Empleado() {Id = "3", Nombre = "Empleado 3", Salario = 3000000},
                new Empleado() {Id = "4", Nombre = "Empleado 4", Salario = 4000000},
            };
 
            // ... Operaciones complejas y calculos del negocio.
 
            return empleados.First(c => c.Id.Equals(idEmpleado)).Salario;
        }
    }

Módulo de Beneficios:

    public class Beneficio
    {
        public List<dominio.Beneficio> ObtenerrBeneficiosEmpleado(string idEmpleado)
        {
            // ... Buscar beneficios del empleado en particular.
 
            // ... Calculos para determinar si el empleado tiene un beneficio o no.
 
            return new List<dominio.Beneficio>()
            {
                new dominio.Beneficio {Nombre = "Prima extralegal 1", Valor = 2000000},
                new dominio.Beneficio {Nombre = "Prima extralegal 2", Valor = 1000000},
                new dominio.Beneficio {Nombre = "Subsidio para hijos", Valor = 500000}
            };
        }
    }

Módulo de Incentivos:

    public class Incentivo
    {
        public List<dominio.Incentivo> ObtenerIncentivosEmpleado(string idEmpleado)
        {
            // ... Buscar incentivos otorgados al empleado con reglas de negocio.
 
            return new List<dominio.Incentivo>()
            {
                new dominio.Incentivo {Concepto = "Bono por cumplimiento", Valor = 200000},
                new dominio.Incentivo {Concepto = "Bono por felicitaciones del cliente", Valor = 200000}
            };
        }
    }

Estos son nuestros módulos con implementaciones concretas, ahora veamos como la fachada usa cada uno de ellos y expone su funcionalidad con una interfaz mucho más simple:

    public class EmpleadoFacade
    {
        public double ObtenerTotalIngresosEmpleado(string idEmpleado)
        {
            var nomina = new Nomina.Nomina();
            var beneficio = new Beneficio();
            var incentivo = new Incentivo();
 
            var salario = nomina.ObtenerSalarioEmpleado(idEmpleado);
            var totalBeneficios = beneficio.ObtenerrBeneficiosEmpleado(idEmpleado).Sum(c => c.Valor);
            var totalIncentivos = incentivo.ObtenerIncentivosEmpleado(idEmpleado).Sum(c => c.Valor);
 
            return salario + totalBeneficios + totalIncentivos;
        }
    }

Como vemos nuestra fachada nos permite obtener los ingresos totales de un empleado en específico, invocando cada uno de nuestros módulos y operando con cada uno de ellos, con el fin de exponer de una manera mucho más fácil la información.

Y por último veamos cómo, nuestro cliente de facturación, en nuestro caso una aplicación de consola hace uso de la fachada:

    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Digite la identificación del empleado para obtener su total de ingresos ...");
            var idEmpleado = Console.ReadLine();
 
            var empleadoFacade = new EmpleadoFacade();
            var salario = empleadoFacade.ObtenerTotalIngresosEmpleado(idEmpleado);
            Console.Write("Los ingresos totales del empleado con identificación {0}, son: {1}", idEmpleado, salario);
            Console.ReadLine();
        }
    }

Como podemos ver este cliente logra acceder a la información de una forma muy simple, y si por algún motivo las reglas de negocio cambian, con respecto a la nómina, beneficios, incentivos, o se crea un nuevo módulo, nuestros clientes no sufrirán impacto, y solo tendremos que modificar nuestra fachada.

Bueno amigos eso es todo de esta muestra acerca del patrón de diseño fachada o Facade pattern, espero sea de utilidad y de interés para ustedes.

Este ejemplo lo puedes descargar de mi repositorio en GitHub

Saludos, y buena suerte!

7 comentarios:

  1. Gracias por tan interesante aporte.

    ResponderEliminar
  2. Hola Gustavo, un saludo.
    Lo principal, me ha parecido muy interesante, pero... el problema que resuelves mediante facade, no sería una implementación simple del patrón Layers?
    Lo siento, pero no se mucho del tema.
    Aprovecho para decirte que me están gustando mucho tus artículos... el de la implementación de Repository, me ha aclarado muchísimas dudas.

    ResponderEliminar
    Respuestas
    1. Hola amigo, primero que todo muchas gracias por leerme y que bueno que te hayan servido mis artículos. El fin del patrón fachada es simplificar acceso a operaciones complejas, centralizar el acceso y dividir en subsistemas para reducir la complejidad, en este ejemplo se usan varias capas o layers, una de ellas es la fachada, dónde se tendrá el acceso a las diferentes operaciones de negocio, como puedes ver en la fachada de Empleado, se invocan tres operaciones complejas y se exponen de una forma muy simple, para que cualquier aplicación las pueda consumir sin mucho trabajo. Podemos hacer un proyecto en tres layers por ejemplo, en este caso la presentación consumiría cada implementación concreta para salario, beneficios e incentivos, y tendría que lidiar con la complejidad de cada uno, como ves en este ejemplo el aplicativo cliente de consola (Aplicación de presentación en este caso) solo se entiende con la fachada y no sabe de implementaciones concretas, lo cual da un valor agregado con respecto a facilidad de uso, desacoplamiento con implementaciones concretas, y reducción de complejidad.

      espero te sirva mi respuesta, saludos!

      Eliminar
  3. muy interesante sin saber e implementado estos conceptos muchísimas gracias por tu forma de explicarlo es muy sencillo.

    ResponderEliminar
  4. Muchas gracias Tavo, me ha sido de gran utilidad!

    ResponderEliminar