Principio de Diseño

Pugna por un diseño de bajo acoplamiento en objetos que interactuan. Esto se refiere a no hacer dependientes nuestras clases que se relacionan y pugnar por hacer un diseño flexible que minimice el impacto del cambio manejando la interdependencia entre objetos para poder modificarla cuando deseemos sin tener que afectar a las clases relacionadas.

Observer

Define una dependencia entre objetos de uno a muchos de modo que cuando un objeto cambia su estado todos sus dependientes son notificados y actualizados automáticamente.

El Patrón Observador es muy usado tal vez lo puedas recordar en interfaces gráficas en los eventos de un objeto, o quizá simplemente hayas escuchado la analogía con "Las revistas y sus suscriptores", en sí ejemplificarlo puede llegar a ser fácil, pero eso no significa que sea sencillo. Como hemos visto en entradas anteriores aplicar un patrón no solo implica poner código aquí y allá, significa que todo tiene un porque y debe ser entendido para se vuelva útil y nos brinde una solución. A continuación haremos una reflexión sobre el patrón Observador, pon mucha atención.

Utilizando la analogía antes mencionada sobre "Las revistas y sus suscriptores" te presentamos al patrón observador, infórmate sobre lo que acontece en Objectville.

¿Sabes cómo funcionan las suscripciones de revistas y periódicos?

  1. Un editor de revistas o periódicos entra en el negocio y comienza a publicar noticias y artículos.
  2. Usted se suscribe a un editor y cada cierto tiempo se le entrega una nueva edición de la revista o periódico. Siempre que usted sea un suscriptor recibirá nuevas ediciones.
  3. Usted se da de baja como suscriptor porque ya no desea recibir más ediciones y las ediciones dejan de ser entregadas.
  4. Mientras exista un editor publicando ediciones existirán personas, empresas, hoteles, aerolíneas suscribiéndose para recibir las ediciones. 
Editores + Suscriptores = Patrón Observador.

Si entendemos esta analogía de suscripciones podemos entender muy fácilmente el patrón observador sólo que nosotros llamaremos al Editor como Sujeto y al Suscriptor como Observador. Echemos un vistazo.

Como vemos en la imagen existe un Sujeto el cual tiene sus observadores (relación uno a muchos) y cuando el sujeto cambia su estado sus observadores son notificados y actualizados automáticamente igual que la forma de trabajo de un Editor y sus suscriptores, el que esta suscrito recibe las ediciones y el que no, no. Viendo el mismo ejemplo de la imagen Duck Object no es un observador de Subject Object pero puede hacerlo si se suscribe notificándole a Subject y empezar a recibir notificaciones y actualizaciones, y de igual forma Mouse Object que es un observador puede dejar de serlo en el momento en que desee, sólo tiene que avisarle al Subject  y dejará de recibir las notificaciones y actualizaciones.

Bien ya vimos un ejemplo muy claro de la forma de trabajar del Patrón Observador ¿Lo haz comprendido? Suena fácil, ¿no?. ¡Aplicalo entonces! . . .  Bien veo que aquí te detuviste y pensaste ¿Cómo implemento el Patrón Observador? ¿Debo usar una interfaz o una clase abstracta para los Observadores y el Sujeto?,  ¿Cómo hago la relación uno a muchos?, ¿Cómo se suscriben los Observadores al Sujeto y cómo dejan de estar suscritos?. Sé que como buen diseñador de patrones ya pensaste algunas cosas e intentaste aplicar los principios de diseño vistos anteriormente y pensaste en el principio de diseño que te presentamos al inicio de este post. Concentra tus ideas y observa el diagrama de clases de la definición del Patrón Observador:
¿Se parece al que pensaste?, ¿Ya viste los principios de diseño aplicados?. Si es tal cual lo pensaste Felicidades eres un gran diseñador de patrones y haz comprendido cómo trabaja el Patrón Observador y sabes aplicar los principios de diseño. Si no fue tal cual lo pensaste te invito a continuar con la lectura y seguir el caso práctico para que lo comprendas a la perfección.

Caso Práctico:
¡FELICIDADES! Su equipo de trabajo acaba de ganar el contrato para construir la próxima generación de la Estación de Monitoreo del Tiempo basada en Internet de Weather-O-Rama, Inc.

La estación del tiempo estará basada en la patente pendiente WeatherData Object de Weather-O-Rama, Inc., la cual rastrea las condiciones actuales del tiempo (humedad, temperatura y la presión atmosférica). Usted y su equipo debe hacer una aplicación la cual muestre 3 diferentes pantallas del tiempo: Condiciones actuales, Estadísticas del tiempo y un Pronóstico simple, todas actualizadas en tiempo real cuando el objeto WeatherData obtenga las mediciones mas recientes. Además Weather-O-Rama desea hacer su estación del tiempo extensible por lo que solicita se haga una API la cuál permita a otros desarrolladores escribir sus propias pantallas del tiempo. 

Weather-O-Rama espera tus diseños y una aplicación alpha para probar, ¿qué esperas?.
Tienes mucho trabajo y debes tomar calma para pensar que hacer al respecto. Como somos muy buena onda, te echaremos una mano y te ayudaremos con la tarea encargada, pero no significa que lo haremos por ti, si pensaste eso estas muy equivocado. Manos a la Obra, primero repasemos que es lo que el cliente te pidió. 
Los 3 elementos en juego en el sistema son: La estación del tiempo, el Objeto WeatherData y las Pantallas del Tiempo que debemos mostrar, por lo que tenemos:

El Objeto WeatherData sabe como comunicarse con la Estación física del tiempo para obtener la actualización de la información. Por lo que nuestro trabajo es hacer una aplicación que implemente el Objeto WeatherData que actualice las Pantallas de tiempo, condiciones actuales, estadísticas del tiempo y el pronóstico. Dicho Objeto nos será proporcionado por el cliente.

Desempaquetando la Clase WeatherData.

Al día siguiente como lo prometió el cliente nos entregó el paquete con la clase WeatherData, echemos un vistazo:

Como vemos en la imagen el cliente nos dejó una pista sobre lo que necesitamos agregar y nuestro trabajo es implementar el método measurementsChanged() el cual actualizará las pantallas del tiempo. Este método es llamado cada vez que existe nueva información de la estación del tiempo. Nosotros no sabemos cómo es que este método es llamado y no debe interesarnos, solo debemos saber que es llamado de alguna forma. Existen 3 métodos más los cuales obtienen la información de humedad, temperatura y presión, y nosotros debemos implementar 3 pantallas que muestren las condiciones actuales, las estadísticas del tiempo y el pronóstico. Además el sistema debe ser extensible debemos crear una API que permita a otros desarrolladores escribir su propio código de nuevas pantallas del tiempo. 
Hagamos una primer implementación de la Clase WeatherData con lo que tenemos.

¡Bien hecho! ahí tienes el primer diseño y porque no la aplicación alpha que el cliente pidió. Muy rápido ¿no?. Demasiado rápido diría yo, lo cuál me hace pensar que creíste que todo estaba correcto. ¿Notaste acaso algo raro en nuestro código? ¡Claro! y los principios de diseño ¿dónde están?, y el patrón observador ¿cuándo lo aplicamos?. Qué bueno que te diste cuenta a tiempo, sino hubieras entregado el horror de código del año. Ahora sí, tomemos los principios de diseño que ya teníamos y detectemos nuestros errores.

Ahora recordemos la definición del patrón observador (apóyate del diagrama que hicimos para el patrón observador y crea el tuyo) y apliquemosla junto a nuestros principios de diseño. Tómate tu tiempo, sabemos que diseñar no siempre es fácil, lo que debes hacer es preguntarte ¿Porque debemos aplicar el patrón observador a esta aplicación? Si respondes a tu pregunta haciendo la analogía de los editores y suscriptores haz dado en el blanco y podrás avanzar rápidamente. Como información adicional toma en cuenta lo siguiente para aplicar el último principio de diseño que te mencionamos al inicio del post.
El poder del Bajo Acoplamiento: Cuando dos objetos tienen bajo acoplamiento, pueden interactuar y tener poco conocimiento uno del otro. El patrón observador provee un diseño de objetos donde los sujetos y los observadores tienen bajo acoplamiento ya que lo único que sabe el sujeto sobre los observadores es que ellos implementan una interfaz en específico, lo que nos hace poder agregar observadores en el momento que queramos sin tener que modificar el sujeto para agregar nuevos observadores. Además podemos rehusar sujetos y observadores independientemente unos de otros y si cambiamos cualquiera de los dos no afectaría a los demás. Esto lo puedes observar en el diagrama del patrón observador. 
Implementación del Patrón Observador y principios de diseño.
¿Ya tienes tu diagrama de clases del Patrón Observador para la aplicación de La estación del tiempo? Comparémoslo.

¿Qué tanto se parece al tuyo?. Como ves hemos creado un diseño que nos permite a partir de que las nuevas mediciones de la Estación del tiempo llegan, actualizar en tiempo real las pantallas del tiempo. Podemos ademas agregar cuantas pantallas nuevas del tiempo deseemos sin necesidad de mover código gracias al bajo acoplamiento. Tenemos encapsaladas las partes que varían y creamos interfaces para poder cambiar en tiempo de ejecución nuestra implementación.
Ahora vayamos a la implementación de nuestro diseño, lo primero que implementremos serán nuestras interfaces.

Borremos de nuestra mente la implementación pasada de la Clase WeatherData, ahora ya conocemos el patrón observador y no tenemos porque dejar ese diseño funcional pero con errores de diseño que nos harían re trabajar. Recuerde que nuestra Clase WeatherDatase ha convertido en nuestro Sujeto concreto y debemos implementar la interfaz <<Subject>> y proveer los métodos registerObserver(), removeObserver() y notifyObservers(), además de implementar el método measurementsChanged() el cual será llamado cuando exista nueva información que actualizar. 

Para fines prácticos y ya que no sabemos en qué momento la Estación Física del Tiempo actualizará los datos crearemos un método setMeasurements() el cuál se encargará de setear los datos simulando la actualización de información enviada por la Estación Física del Tiempo.

Por último hagamos una implementación de las pantallas del tiempo, aquí sólo te mostraremos la implementación de la pantalla de condiciones actuales pero puedes obtener el código completo de la página de headfirstlab.
Y ahora las pruebas, sólo necesitamos unir las piezas y tendremos nuestro sistema WeatherStation listo para entregar.
¿Así imaginabas la implementación de las pantallas del tiempo?, ¿Te diste cuenta en que momento un observador se suscribe? Como se observa los observadores mantienen una relación con su sujeto y ellos deciden suscribirse al momento de ser creados para estar actualizados, si nosotros dejamos la suscripción en el constructor como se ve en la imagen tenemos la oportunidad de que si deseamos dejar de estar suscritos lo podemos hacer en tiempo de ejecución ya que el sujeto ha sido creado y mantenemos una relación a él, y de igual forma podríamos cambiar de sujeto para actualizar nuestros datos desde otro lugar.

¡FELICIDADES! Ahora ya sabes como diseñar el Patrón Observador. Por tu gran esfuerzo te proporcionaremos una segunda implementación en código del Patrón Observador (by @juanitodread) para que la puedas ver, probar, extender, etc., ¡Disfrútala!.

Aquí el código adicional del Patrón de Diseño Observador.

NOTA: Java maneja su propia implementación del patrón observador en el paquete java.util, que utiliza la clase Observable como el sujeto y la interfaz Observer como el observador. Esta implementación provee de mucha funcionalidad fuera del contexto que puede ser de gran utilidad. Sin embargo observa que Observable es una clase y por tanto deberás extenderla si deseas crear un sujeto concreto lo que provoca un rompimiento a nuestro principio de diseño "Favorece la composición en vez de la herencia". Esto no significa que sea por completo malo pero promueve un diseño no tan flexible como el que creamos, toma en cuenta la funcionalidad que te puede dar esta implementación de java y evalúa tú situación para implementarla o crear la tuya propia, porque ahora ya sabes como así que no tengas miedo de crear la tuya.

¿Entendiste el patrón?, ¿Tienes dudas?, no olvides preguntar, comentar, sugerir o corregir algo si lo deseas, con gusto responderé a cualquiera de tus comentarios.
Espero les sea de utilidad y puedan aprender algo nuevo con esta serie de posts, esperen muy pronto el siguiente. ¡Saludos!

1 comentario

Seguidores

Google+ Followers

MarceStarlet. Con la tecnología de Blogger.