El patrón Command

El patrón Command

El patrón Command es, en un lenguaje muy poco técnico,  la implementeación de un código que permite la creación de peticiones por parte del usuario, su almacenamiento y posterior ejecución sobre un receptor. Nos permite desacoplar el objeto que dispara una acción del objeto que la realiza.

Podemos en base a la «definición» anterior deducir que existen 4 entidades que interactúan entre sí.

  1. El cliente que realiza la petición.
  2. La propia petición.
  3. Un elemento intermediario entre el cliente y el receptor.
  4. El receptor que se encarga de ejecutar la petición.

El cliente es el sujeto que crea la petición en base a dos cuestiones: qué quiere hacer y sobre quién quiere hacerlo.

La petición es el elemento central del patrón. Contiene el código a ejecutar sobre el receptor y por ende, una referencia a este.

El elemento intermediario es el encargado de almacenar las peticiones y provocar su ejecución cuando el cliente lo necesite, o cuando se considere oportuno por cualquier otro motivo.

El receptor simplemente es el sujeto pasivo de la ejecución del comando disparado por el intermediario.

patron command uml

ODIO profundamente el diagrama UML «oficial» del patrón Command, porque creo que despista más que aclara a la hora de comprender por primera vez este patrón. ¿Como es posible que el intermediario no tenga ningún tipo de relación con el cliente y el receptor si? Es necesario intentar comprender por qué está así expuesto el diagrama UML.

El intermediario o invoker no tiene por que tener una relación directa con el cliente, como se ve en el diagrama. Puede o puede no tener relación, a fin de cuentas el cliente que exponemos aquí sólo tiene la obligación de crear el comando y vincularlo con su receptor, pero no de usar el invocador…¿no? El invocador puede estar manejado por un proceso independiente, otro cliente que puede llamar recursivamente cada cierto tiempo a la ejecución de sus comandos por ejemplo.

Nótese por tanto que el cliente que crea el comando puede no ser necesariamente el cliente que llame a su ejecución, aunque por regla general sea así.

En un diagrama de secuencias se aprecia mejor el funcionamiento del patrón, y cómo el invocador está desacoplado del receptor.

Veamos un ejemplo práctico:

Supongamos que nosotros (los clientes) queremos sacar dinero (petición) de un cajero automático (intermediario) de nuestra cuenta bancaria (receptor).

No sabemos cómo es la lógica interna del banco para darnos dinero, ni cómo funciona la máquina por dentro. Solo sabemos que necesitamos ejecutar la acción de sacar dinero sobre nuestra cuenta, así que le decimos al intermediario lo que queremos, generando un comando a medida.

El cajero recibe el comando, parametrizado con el dinero que queremos sacar y la cuenta sobre la que se ejecuta. En un momento determinado, llama a la ejecución de su método, que lleva implícito el código ejecutable que nosotros no conocemos.

El banco recibe las ordenes, haciendo los cambios oportunos en la cuenta, guardando un registro de la transacción, cobrando comisión si hubiera, etc.

Deshacer el último comando

¿Que pasa si el invocador he ejecutado un comando que no debería y necesitamos devolver el receptor de la acción a su estado previo? Esta es una de las características del patrón Command, que nos permite deshacer los cambios de la ultima llamada realizada.

Si todos los comandos tienen un método execute() que se encarga de realizar una operación, podemos obligar a esos mismos comandos a implementar un método definido en la interfaz que deshaga ese cambio. Por ejemplo si tenemos un comando que se encarga de cambiar el volumen de un altavoz, necesitariamos guardar el estado del volumen cada vez que llamemos al método execute() por si acto seguido queremos deshacer los cambios.

El problema de la infinidad de clases comando concretas

¿Te has dado cuenta de la cantidad de comandos concretos que necesitaríamos si quisiéramos crear un altavoz con 100 modos distintos de ejecutarse? Que se iluminase, que tuviera un regulador de volumen, de bajos, de agudos… Un comando para cada modo de cada característica de un solo aparato. ¡Acabaríamos teniendo una cantidad enorme de clases sin apenas código! Afortunadamente, a partir del JDK8, podemos usar las expresiones lambda, que nos permiten solucionar este problema definiendo la implementación del método abstracto que hereda una clase anónima de una interfaz funcional sin necesidad de crearla nosotros.

 

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.

 

El patrón Observer en Swing

El patrón Observer en Swing

Esta entrada sirve para poner en práctica todo lo aprendido del patrón Observer en esta y esta entrada del blog. Si no sabéis qué es el patron Observer o teneis dudas, echadles un vistazo antes.

El patron observer en Swing es un poco más intrincado de lo que estudiamos en la teoría la primera vez, sobre todo por la gran cantidad de eventos y clases que hay, pero con un diagrama UML para una clase concreta, creo que podremos abstraer esta lógica.

Pongamos por ejemplo el caso de un JComboBox.

El JComboBox es un componente de Swing que nos permite seleccionar una opción de una lista desplegable, lo que nos da una pista: debe ser algo que se deba observar y este notificará cuando un evento como la selección de un ítem tenga lugar. Tendrá presumiblemente el rol de Observable.

Si echamos un vistazo a su implementación, nos encontraremos con que se compone entre otros, de un objeto de tipo EventListenerList. Si investigamos un poco, vemos que es un objeto muy sencillo , y la base del patrón Observer en Swing. No en vano JComponent (su clase padre) tiene este mismo campo, siendo según la documentación «The base class for both standard and custom components that use the Swing architecture».

Pongamos lo que sabemos por ahora en un diagrama UML: Un Componente de tipo JComboBox tiene un campo donde se almacenan diferentes objetos que extienden de la clase EventListener.

Click para ampliar

Ya tenemos al elemento Observable más o menos definido. Ahora falta definir el Observador, que puede ser cualquier cosa, siempre y cuando le podamos enviar mensajes.

Si recordamos, el observador debe implementar un método para recibir notificaciones. Ese método es el que se llama desde el elemento observado para desencadenar un algoritmo del que ya no es responsable.

¿Recuerdas de qué tipo son los oyentes en la lista de tipo EventListenerList del objeto Observable? Todos heredaban de una de tres interfaces: ActionListener, ItemListener y PopupMenuListener. Pues por definición, si queremos meter un oyente en esa lista para que sea notificado, debe implementar una de estas tres interfaces e implementar los métodos correspondientes.

El cómo llama al evento es algo que dejo para las personas que tengan paciencia para comprender a fondo como funciona Swing. Se ven implicadas otras clases y supondría desviarse del tema demasiado. Pero el cuándo, es fácil de adivinar: cuando se llaman a los métodos que comienzan por fire, por ejemplo fireActionEvent().

Así que si queremos que nuestra clase observadora sea notificada de un evento de un JComboBox solo tendremos que seguir estos dos pasos:

  1. Implementar la interfaz del evento que queramos escuchar y añadirle una funcionalidad.
  2. Añadir como oyente a nuestra clase observable de tipo JComboBox.

Click para ampliar

Y por último…

No hace falta decir que este modelo está muy simplificado, para facilitar la comparación con el modelo teórico. Muchas más interfaces heredan de EventListener y el JComboBox implementa varias interfaces para escuchar (es a la vez observadora y observada).

Os animo a bucear por el código fuente del JDK alguna vez en clases no muy enrevesadas. Es un gran ejercicio tanto para conocer el lenguaje como para coger fluidez en la lectura de código.