Una larga ausencia


Ya casi han pasado cuatro meses desde la última vez que actualicé el blog, y por ello quisiera pedir disculpas. Cambio de trabajo, cambio de ciudad, inicio de un Máster y responsabilidades sociales y familiares han mermado de forma importante mi tiempo libre, por lo que muy a mi pesar no he podido (al menos) finalizar la serie dedicada a los patrones de diseño aplicados al entorno .NET.

Sin embargo, I’ll be back. No soy persona que guste de dejar las cosas a medias, y en cuanto saque un poco de tiempo, me pondré manos a la obra para finalizar los patrones que quedan pendientes y seguir dando guerra por estos lares.

Por lo tanto, ante la pregunta de que si publicaré más patrones, la respuesta es “sí”. Lo que no puedo asegurar es cuándo. Pero intentaré que no sea muy tarde.

Y por supuesto, agradezco vuestras críticas y vuestros comentarios.

Nos vemos pronto.

Patrones de Comportamiento (VI): Patrón Observer


Objetivo:

“Definir una dependencia uno-a-muchos entre objetos de forma de que, cuando el estado de uno de ellos cambia, todos los objetos dependientes son notificados y actualizados de forma automática”.

Design Patterns: Elements of Reusable Object-Oriented Software

Podemos afirmar sin rubor alguno que el patrón Observer es uno de los más importantes (y utilizados) de todos los patrones de diseño vistos hasta el momento. Su filosofía es simple: un objeto, denominado sujeto (Subject) posee un estado. Cuando su estado cambia, es capaz de “avisar” a sus subcriptores (Observers) de este cambio de estado. De este modo, los objetos suscritos al objeto no tienen que preocuparse de cuándo se produce un cambio de estado: éste se encargará de informar de forma activa a todos aquellos objetos que hayan decidido suscribirse.

Este tipo de suscripción puede ser de dos tipos:

  • Suscripción push: el objeto informa a sus suscriptores con sus valores tan pronto como su estado cambie.
  • Suscripción pull: el objeto es interrogado por sus suscriptores si su estado ha cambiado desde la última vez que se tanteó.

Este esquema respeta al máximo el principio de bajo acoplamiento. El Subject y el Observer pueden interactuar entre ellos, pero apenas tienen conocimiento del uno sobre el otro. Dado que hemos basado el diseño en abstracciones, no en concreciones, no será necesario modificar el Subject para añadir nuevos Observers (bastará con que implemente la interfaz IObserver). Del mismo modo, un Observer podrá suscribirse a más de un Subject si éste implementa la interfaz ISubject.

(más…)

Patrones de Comportamiento (V): Patrón State


Objetivo:

“Permitir que un objeto modifique su comportamiento cuando su estado interno cambie. Parecerá que el objeto cambia de clase”.

DesignPatterns: Elements of Reusable Object-Oriented Software

El patrón State tiene la misión fundamental de encapsular el comportamiento de un objeto dependiendo del estado en el que éste se encuentre. ¿A qué nos referimos con estado? Estrictamente hablando, podemos definir el estado de un objeto como el conjunto actual de los valores de los atributos de un objeto. Desde un punto de vista más coloquial, y refiriéndonos al patrón que estamos presentando, podríamos definir un estado como un conjunto de características que harán que el objeto tenga unas características concretas. O hablando en plata: desde el punto de vista de la orientación a objetos, podemos decir que el estado de un vehículo es de velocidad instantánea igual a cero, sin consumo de combustible, a una distancia de entre cero y veinte centímetros de la acera y con el habitáculo vacío. Desde un punto de vista coloquial (que ahora mismo es el que nos interesa), podemos decir que la suma de esos atributos nos informa de que el vehículo se encuentra en estado aparcado.

(más…)

Patrones de Comportamiento (IV): Patrón Strategy


Objetivo:

“Definir una familia de algoritmos, encapsular cada uno de ellos y hacerlos intercambiables. Strategy permite cambiar el algoritmo independientemente de los clientes que lo utilicen”.

Design Patterns: Elements of Reusable Object-Oriented Software

En el artículo anterior veíamos cómo un patrón de diseño puede ayudarnos a encapsular distintos algoritmos a partir de una “plantilla” cuyos hijos se encargaban de especializar. El patrón Strategy, por su parte, no bucea en los detalles, sino que va un paso más allá: encapsulará un algoritmo completo ignorando los detalles de su implementación, permitiendo intercambiarlo en tiempo de ejecución para permitir actuar a la clase cliente con un comportamiento distinto.

El nombre de este patrón evoca la posibilidad de realizar un cambio de estrategia en tiempo de ejecución sustituyendo un objeto que se encargará de implementarla. No nos preocupará el “cómo”. De hecho, ni siquiera nos importará “el qué”: la clase que actúa como interfaz del patrón únicamente tendrá que exponer el método o métodos que deberá invocar el cliente.

(más…)

Patrones de Comportamiento (III): Template Method


Objetivo:

“Permitir que ciertos pasos de un algoritmo definidos en un método de una clase sean redefinidos en sus clases derivadas sin necesidad de sobrecargar la operación entera”.

Design Patterns: Elements of Reusable Object-Oriented Software

Si el patrón Command nos permite encapsular una invocación a un método, el patrón Template Method o Método Modelo establece una forma de encapsular algoritmos. Este patrón se basa en un principio muy sencillo: si un algoritmo puede aplicarse a varios supuestos en los que únicamente cambie un pequeño número de operaciones, la idea será utilizar una clase para modelarlo a través de sus operaciones. Esta clase base se encargará de definir los pasos comunes del algoritmo, mientras que las clases que hereden de ella implementarán los detalles propios de cada caso concreto, es decir, el código específico para cada caso.

El procedimiento es sencillo:

  • Se declara una clase abstracta, que será la plantilla o modelo. Esta clase definirá una serie de funciones y métodos. Aquellas que sean comunes estarán implementadas. Aquellas que dependan de cada caso concreto, se declararán como abstractas, obligando a las clases hijas a implementarlas.
  • Cada clase derivada implementará los métodos específicos, acudiendo a la clase base para ejecutar el código común.
  • La clase base también se encargará de la lógica del algoritmo, ejecutando los pasos en un orden preestablecido (las clases hijas no deberían poder modificar el algoritmo, únicamente definir la funcionalidad específica que tienen que implementar).

Dado que la clase padre es la que se encarga de llamar los métodos de las clases derivadas (los pasos del algoritmo estarán implementado en la clase base), se trata de una aplicación manifiesta del principio de inversión de dependencias: la clase base no tiene por qué saber nada acerca de sus hijas, pero aún así, se encargará de invocar su funcionalidad cuando sea necesario. El principio de Hollywood (“no nos llames, nosotros te llamaremos”) vuelve a entrar en escena.

(más…)

Patrones de Comportamiento (II): Patrón Command


Objetivo:

“Encapsular una petición como un objeto, de modo que puedan parametrizarse otros objetos con distintas peticiones o colas de peticiones y proporcionar soporte para realizar operaciones que puedan deshacerse”.

Design Patterns: Elements of Reusable Object-Oriented Software

Cuando decimos que un patrón es “estructural” es sencillo imaginar que su cometido será modelar las clases de tal forma que cumplan un cometido concreto. Sin embargo, el concepto de diseñar clases orientando su funcionalidad hacia el comportamiento es algo más complicado. El patrón command u orden (como decía mi profesor de programación en primero de carrera, command se debería traducir por órden, no por comando, ya que un comando es un señor militar que pega tiros en la selva) tiene como objetivo encapsular la invocación de un método. Dicho así sin más, suena sencillo de entender pero… ¿cómo lo implementamos? La definición, a diferencia del patrón anterior, es un conglomerado de términos incomprensibles, ¿verdad? Encapsular una petición como un objeto. Vale, lo pillo. Pero ¿parametrizarse? ¿Soporte para realizar peticiones que puedan deshacerse?

(más…)

Patrones de Comportamiento (I): Patrón Iterator


Objetivo:

“Proporcionar una forma de acceder a los elementos de un objeto agregado de forma secuencial sin exponer sus detalles”.

Design Patterns: Elements of Reusable Object-Oriented Software

Pese a que no seamos conscientes de ello, cuando programamos utilizamos el patrón Iterator a diario. Casi todas las estructuras de datos que representan colecciones utilizan de algún modo este patrón para proporcionar acceso secuencial a los elementos que las conforman, y tanto Java como .NET ofrecen interfaces que nos invitan a implementar este patrón codificando su comportamiento.

Ojo al detalle: hemos dicho recorrer secuencialmente, esto es, hacer uso de un proceso que sea capaz de situarse en el primer elemento de una colección y obtener la información de ese contenido. Tras esto, dado que hemos dicho que se trata de una operación secuencial, deberemos ser capaces de pasar del elemento actual al elemento al siguiente, obteniendo también su contenido. Por último, será necesario implementar algún mecanismo que nos informe si hemos alcanzado el final de la colección para detener el proceso de iteración.

Por lo tanto, el patrón Iterator debe proporcionar la siguiente funcionalidad:

  • Obtener una referencia al elemento actual de la colección.
  • Obtener una referencia al siguiente elemento de la colección (el situado a continuación del elemento actual).
  • Obtener información sobre si existen más elementos después del actual.
  • Reiniciar la colección para que el iterador apunte nuevamente al primer elemento de la colección.

Seguramente podremos pensar que no tiene mucho sentido implementar nuestro propio patrón Iterator, ya que prácticamente todas las colecciones implementan todas estas operaciones (e incluso alguna más). Sin embargo, existirán muchos supuestos en los que nos será útil.

(más…)