El patrón Facade

El patrón Facade

Imagina un sistema lleno de clases necesarias para realizar una determinada acción. Pongamos por ejemplo que queremos encender un ordenador, y tuvieramos que hacerlo de forma manual, llamando al POST, encendiendo el sistema de ventilacion, cargando el OS en la RAM, etc. ¿Sería un engorro verdad? Pues el botón que pulsamos y que desencadena una serie de procesos por nosotros es el patrón Facade. Nosotros no tenemos ni la menor idea de qué pasa dentro de la computadora, pero funciona simplificando los pasos que necesitamos, y si tenemos los conocimientos necesitarios incluso podemos refinar su proceso, es decir, no se nos veta el acceso a los componentes de los que la fachada nos abstrae.

Como siempre veamos un diagrama UML de las clases con las que vamos a ejemplificar el patrón.

 patron facade uml

Sobra decir que el anterior diagrama se ha hecho complejo a propósito, evitando desacoplamientos, etc para comprender mejor las ventajas de la fachada que provee el patrón.

Este diagrama con dependencias entre sí y sin un orden de carga definido es dificil de manejar y entender. Si quisieramos emular el comportamiento correcto del arranque de este sistema en un main() tendríamos algo similar a esto:

Desde luego, nada facil de leer, y con muchisimas dependencias. El patrón Facade nos permitirá generar una clase que llamando al menos numero de métodos posibles, automatice todo este código, abstrayendo al usuario del funcionamiento del programa y en este caso, evitando que se equivoque en el orden de ejecución, como podría ser administrar la corriente después de ejecutar el POST.

Si nos fijamos en el diagrama UML anterior vemos que pueden existir clases como FirmwareMotherboard que con su método ejecutarPOST() se encargan de abstraer la verificación y encendido de componentes como la Ram o los ventiladores(¡ya tenemos un ejemplo pequeño del patrón!), pero aun así, se nos queda corto para abstraer el encendido total del ordenador, necesitamos una fachada para todo el conjunto de clases y no solo para el encendido de algunos componentes. Algo en codigo similar a esto:

Y representado en UML así:

patron facade uml

Hemos conseguido encender el ordenador pero el cliente no ha necesitado conocer los entresijos de su lógica, simplemente ha llamado al método encenderOrdenador() de la clase TurnOnOffComputerFacade. ¡Y ojo! ¡Como hemos dicho no es la unica fachada del ejemplo!

En esencia el patrón Facade sirve para encapsular llamadas a métodos de distintas clases desde una clase que las contiene a todas y abstrae al usuario de su manejo.

Sin embargo este patrón puede tener una contrapartida con el que hay que tener cuidado: el no seguimiento del Principio de Mínimo Conocimiento.

El patrón Adapter

El patrón Adapter

La mejor forma de comenzar a comprender el patrón Adapter es presentar un símil con objetos de la vida real. Imaginemos que tenemos una lujosa y moderna tarjeta gráfica con salidas hdmi pero solo disponemos de una antigua pantalla con entrada VGA y  un cable hdmi. Es evidente que no podemos pasar información de un emisor digital a un receptor analógico, por lo que necesitamos algo capaz de traducir esa información entre ambos.

patron adapter uml

En este caso el adaptador se encargaría de transformar la salida digital en analógica haciendo la información accesible para el monitor VGA. Pongamos ahora un ejemplo de programación. Tenemos un conjunto de clases que representan objetos con una funcionalidad muy similar, por ejemplo aviones. Los distintos tipos de aviones heredan de una clase abstracta llamada Avión, tal y como se muestra en el siguiente UML:

patron adapter uml

Posteriormente creamos una clase Aeropuerto. Esta clase aeropuerto está pensada para almacenar aviones, por lo que creamos una lista de este tipo de objetos en uno de sus atributos. Pero unas semanas más tarde, nos damos cuenta de que ese aeropuerto no almacena solamente aviones, sino que también puede almacenar helicópteros… e incluso otro tipo de objetos como drones, o dirigibles.

patron adapter uml

En este momento nos planteamos las siguientes dos soluciones:

  • Hacer que Helicóptero herede de Avión.
  • Crear una interfaz (Aterrizable) para todos los objetos, hacer que la implementen tanto aviones como helicópteros y así poder almacenarlos en una lista del aeropuerto de tipo List.

La primera solución es un realmente mala. La clase abstracta Avion puede implementar métodos en el futuro incompatibles con los helicópteros, como por ejemplo desplegarFlaps() que no poseen un equivalente para los helicópteros, por lo que descartamos esta opción enseguida. La segunda opción, aunque deseable, no es posible en todos los casos. Por ejemplo, se puede dar el caso de que la clase forme parte de una API y/o no podamos modificar su código fuente. En ese caso tenemos que crear un adaptador que haga pensar que nuestros helicópteros son aviones. ¿Cómo hacemos esto?

  1. Creando una nueva clase que extienda de avión y que contenga un helicóptero
  2. Implementando los métodos de la clase abstracta de forma que se comporten como lo haría el helicóptero que lo contiene.

Siguiendo con el ejemplo del diagrama UML anterior y los dos pasos mencionados, la clase adaptadora nos quedaría de la siguiente forma:

Ahora la clase principal puede contener helicópteros siempre que estén contenido en un adaptador e incluso puede tratarlos como si fueran aviones, pero con el comportamiento de un helicóptero, de forma que cuando se llame a un metodo como aterrizar, la lógica de los mismos dependa del tipo de avion concreto o del adaptador de un objeto distinto. El diagrama UML final quedaría de la siguiente forma:

patron adapter uml

El patrón adapter es muy útil para situaciones en las que necesitemos gestionar distintas clases con comportamientos parecidos pero no podamos realizar cambios en el código fuente para abstraer una interfaz común a todas ellas. Por lo tanto, como ya mencionamos, puede ser muy útil para manejar cierta clase de APIs en nuestros programas.

El patrón Singleton

El patrón Singleton

En ocasiones necesitamos un objeto común a toda la aplicación. Un objeto del que solo queramos una instancia. Normalmente este tipo de objetos se relacionan con objetos con una función específica para toda la aplicación, como por ejemplo un pool de conexiones a una base de datos o las factorías concretas de un patrón Factory. Para proporcionar la funcionalidad del patrón Singleton debemos tener en cuenta tres cosas:

  • Proveer una manera de evitar más de una instancia de la clase.
  • Crear un punto de acceso único a la clase.
  • Tener cuidado con la concurrencia de la aplicación y sus diferentes hilos.

Para el primer y segundo punto debemos considerar dos cosas: la primera es que si queremos un objeto que comparta su estado en toda la aplicación, este objeto deberá tener ser por definición, estático, y la segunda es que si queremos una sola instancia de este, debemos proveer algún tipo de mecanismo para averiguar si existe una instancia creada de este objeto. Una forma de conseguir ambas cosas puede ser la siguiente:

Hemos creado un constructor privado y de esta forma hemos forzando la creación de un objeto estático en un método público que chequea si está inicializado. En caso de no estarlo, lo inicializa y en caso de ya estar inicializado lo devuelve, pero nunca lo crea dos veces.

Nunca lo crea dos veces… a no ser que se de la circunstancia de que dos o más hilos independientes llamen al mismo tiempo el método y chequeen paralelamente que no existe el objeto… en cuyo caso tendríamos dos instancias creadas y un gran problema.

¿Cómo lidiar con el problema del multithreading sobre un método? Java provee la palabra reservada synchronized para evitar que dos o mas hilos ejecuten simultáneamente el mismo bloque de código. Si eres de los que crees que la sincronización es un recurso caro de implementar en términos de rendimiento, no te preocupes, porque parece ser que está muy sobrevalorado ese coste1. Sin embargo, si te sigue preocupando mucho el tema del rendimiento, puedes delegar la inicialización de tu objeto en tiempo de carga de la clase (que es por definición thread-safe) de la siguiente forma:

No te olvides de que si tu objeto va a ser escrito y leído varias veces tendrás que completar tu implementación con

Si por ultimo eres un paranoico o paranoica de la posibilidad de dos instancias de tipo tu Singleton en la misma aplicación deberías anota tu clase como final y evitar la clonación de tu objeto sobrescribiendo el método clone() que todos los objetos heredan de Object.

Por curiosidad, el diagrama UML para una clase Singleton es el siguiente:

1-https://www.ibm.com/developerworks/java/library/j-jtp04223/index.html

 

El patrón Factory

El patrón Factory

El patrón Factory consiste ni más ni menos que en delegar la creación de objetos en un componente aislado.

Puede que no te diga mucho la frase anterior, pero eso es porque no has visto todavía las ventajas de una constante en todos los patrones de diseño: el desacoplamamiento entre componentes. Por ejemplo, imaginemos que una clase llamada Empresa necesita devolver un objeto en función de un input del usuario por teclado.

La clase Main y la clase Electrodoméstico están altamente acopladas. ¿Por qué? Porque un cambio en los electrodomésticos (la desaparición de un producto, la inclusión de otro) obliga a modificar el código fuente de la clase Main. Por eso, el primer paso para hacer un buen código es separar lo que varía de lo que permanece constante, y de esta forma generar espacios de código donde el mantenimiento del programa esté más controlado.

Veamos la representación del anterior snippet de código en un diagramas UML donde los componentes están altamente acoplados.

Vemos que la clase Main depende de tres clases (y estas clases pueden variar con el tiempo) por lo que tenemos el problema de que nuestro núcleo de la aplicación, el componente Main, va a ser cada vez más complicado de escalar a medida que avanza la vida de la aplicación. Es urgente separar el componente principal de esta funcionalidad ¿pero como lo hacemos? Creando otro componente.

Volviendo al código anterior: ¿que funcionalidades vemos en el programa? Principalmente dos: la entrada y salida al usuario de los datos y la creación de los objetos.

Por supuesto, podemos separar casi tanto como queramos las funciones en funciones más concretas, pero esta entrada no pretende tratar sobre arquitectura de software sino sobre el patrón factory, que consiste ni más ni menos que en crear un componente cuya función se la de la instanciar objetos.

Ahora tenemos una clase llamada ElectroCreator que se encarga de instanciar las clases concretas en función de un parámetro que le pasa la clase Main. Main ya no tiene que saber cómo crear el objeto, no es su función, sólo sabe que puede llamar al método de un componente que sí le devuelve un objeto. Y cómo lo haga le da igual mientras funcione.

Crear un componente por cada funcionalidad de la aplicación es en programación orientada objetos el abc de cualquier proyecto. Nos da muchísima más flexibilidad a la hora de mantener y testear, dado que está altamente aislado de otros componentes con los que interactúa. En desarrollo esto se traduce en una mayor independencia entre equipos y por tanto una mayor productividad. ¡Pero de alguna forma tienen que comunicarse los componentes entre sí! Si estuvieran completamente aislados no podrían hacer nada en conjunto. Efectivamente, y esto se hace gracias a elementos que abstraen el componente de su funcionalidad concreta: las interfaces.

Las interfaces nos permiten decirle a un objeto: «puedes ejecutar los siguientes métodos sobre esta otra serie de objetos, y no sabrás cómo lo hacen, pero funcionarán como esperas que funcionen y/o te retornarán el valor que esperas que retornen». ¡No más código funcionalmente distinto en la misma clase! ¡Un componente, una función!

Especializándonos en el patrón Factory

Si analizamos más detenidamente el ultimo snippet con lo que acabamos de decir,  nos damos cuenta de que podemos mejorarlo.

Imaginemos que podemos producir varios de tipos de microondas, lavadoras y neveras. Cada uno de estos tipos tendrán un consumo determinado y unas características determinadas.

Lo primero que podríamos pensar como desarrolladores es «no pasa nada, cada objeto puede tener esos atributos y ya les daremos el valor cuando creemos la instancia concreta. ¡Error! Hemos creado el patrón Factory para desacoplar precisamente la creación de los objetos. Queremos que Main tenga en su poder, simplemente llamando al creador concreto, el objeto que necesita.

Por ejemplo, podemos crear dos tipos de electrodomésticos, de gama básica y premium con valores distintos en sus atributos, y podemos hacerlo de dos formas gracias al patrón Factory. Porque en realidad existen dos tipos de patrón Factory.

Patrón Method Factory

El patrón Method Factory consiste en crear una clase por cada objeto que se pueda crear. Por ejemplo, en nuestro caso tendríamos una clase ElectrodomesticoFactory abstracta tantas subclases como productos vendamos, y cada una de ellas crearían el producto de una determinada forma.

Ahora en el Main solo tendremos que preocuparnos de obtener la referencia correcta del tipo de creador de electrodomésticos que queramos.

¿Que hemos conseguido creando la interfaz con el patrón Method Factory? Hemos desacoplado  aún más la clase con la que nos comunicamos desde el Main con las implementaciones concretas de los productos, de forma que si creamos nuevos tipos de productos, no tenemos que cambiar nuestra interfaz, solo crear una subclase de esta. Es decir, hemos cumplido con la máxima open-closed.

Patrón Abstract Factory

A diferencia del Method Factory, el patrón Abstract Factory crea una interfaz que agrupa varios métodos constructores pero para objetos diferentes. Veámoslo mejor con un diagrama:

Este patrón por tanto, crea una interfaz con métodos creadores de varios productos y los creadores concretos decidirán cómo se construyen y el tipo concreto a construir. Es lo que parece: una suerte de agrupación de clases concretas del patrón Method Factory.

Las diferencias fundamentales entre los dos patrones

Es normal confundirlos porque hacen algo muy parecido a primera vista y normalmente se pueden usar indistintamente, con dos grandes puntos a tener en cuenta:

  1. El patrón Abstract Factory podría requerir sobrescribir varias clases si se crea un elemento nuevo. En nuestro caso, si introducimos un lavavajillas, tendríamos que heredar createLavavajillas() en el creador concreto pero implicaría más o menos trabajo en función de nuestra aplicación y de cuántas formas de construir electrodomésticos (o subclases de la factoría abstracta) tengamos. Por el contrario, con el patrón Method Factory, solo tendríamos que crear una nueva clase que extendiera de la factoría abstracta.
  2. El patrón Method Factory tiene como contrapartida que si existen muchos elementos concretos que se pueden construir, y muchas formas de construirlos, es un método poco práctico de implementar*.
  3. El patrón Abstract Factory es muy útil para componer objetos. Pasando por ejemplo como argumento al constructor de un objeto una referencia a una factoría concreta, podemos obtener multitud de objetos en tiempo de ejecución, mientras que con el patrón Method Factory, esto sería mucho más engorroso, ya que deberíamos pasar una referencia al mismo constructor por cada objeto que quisiéramos crear.

*Aunque canónicamente se suele utilizar como ejemplo una subclase creadora concreta por producto, es posible (pagando un precio en manteniemiento) parametrizar el método creador. De esta forma podemos obtener varios electrodomésticos en un sólo creador concreto, que podría agrupar varios electrodomésticos según por ejemplo la calidad de su construcción. Sería una suerte de híbrido entre los dos patrones. Esto demuestra que los patrones no son una ley inmutable, sino meras herramientas con pros y contras que valorar.

El patrón Decorator

El patrón Decorator

El patrón Decorator se usa para componer dinámicamente una Clase. Si entiendes el patrón Strategy que explicamos aquí, no te será dificil entender el patrón Decorator.

Imagina que quieres «decorar» un objeto añadiendole multitud de objetos relacionados. Pongamos por ejemplo que queremos hacer una carta para un restaurante. Podríamos crear una clase llamada Comida con multitud de campos que señalasen la cantidad de cada ingrediente. Esta clase comida nos serviría para representar cualquier plato… a primera vista.

Podríamos sobrevivir con este esperpento  de código… la primera semana. En cuanto queramos escalar la aplicación para añadir nuevos ingredientes, nos encontraremos entrando y saliendo del código fuente, por no hablar de los cambios en el precio. Por supuesto podríamos componer esta clase con infinidad de objetos, pero afortunadamente existe un patrón que no solo te permite componer una comida con los ingredientes justos y necesarios, sino que encima te permite crear cualquier tipo de plato en tiempo de ejecución.

Se acabó el crear una clase para cada objeto. Ahora podemos tener una clase que se componga de elementos a medida que los vayamos necesitando, algo similar al patrón Strategy pero acumulativo.

¿Hasta ahora se parece mucho a un patron Strategy no? Pero nos falta poder hacer el componente Comida de los ingredientes acumulativo y no es muy complejo, pero hay que poner atención.

  1. Pasaremos la referencia de un ingrediente (que contendrá la comida acumulada) al nuevo ingrediente para actualizar su atributo Comida. De esta forma, cada ingrediente que creemos guardará su valor.
  2. Extenderemos los ingredientes para que hereden de Comida. Si no lo hacemos, los objetos que contienen la comida y que estamos pasando a otros constructores no podrían ser casteados al tipo del atributo.

Puede resultar bastante lioso en un principio, sobre todo si es la primera vez que lo ves, así que recapitulemos:

  1. Tenemos una clase Comida que queremos decorar.
  2. Creamos los decoradores, que son los ingredientes.
  3. Los ingredientes se crean obteniendo la referencia de una comida y guardándola en un atributo.
  4. Para acumular los ingredientes.
    1. Hacemos que extiendan Comida.
    2. Pasamos el antiguo ingrediente en el constructor del nuevo y guardamos su referencia.
    3. Repetimos el paso anterior hasta que queramos.

En un código muy sencillo (quitando cualquier tipo de abstracción) sería:

Fijaros en que para calcular los valores teniendo en cuenta las comidas acumuladas, se usa el atributo que hemos añadido para recuperar el valor, provocando un «efecto cascada».

Os recomiendo copiar el código de arriba y debuguearlo para comprender el flujo del programa y del patrón.

¿Cómo podríamos mejorar este código?

Si quisieramos crear implementaciones concretas de comida (comidas ya predefinidas) podríamos abstraer la clase comida y utilizar los ingredientes sobre estas clases, como muestra el siguiente UML más reconocible del patrón.