19. Observer: También conocido como el patrón "Publish-Subscribe" es un patrón de diseño de comportamiento, que define una relación de uno a muchos de tal manera que cuando un objeto cambia su estado, todos los objetos dependientes son notificados de la actualización automáticamente. Nos permite crear objetos observables que mantienen una lista de observadores y les notifica a éstos de cualquier cambio en su estado, normalmente llamando a uno de sus métodos. Está relacionado con algoritmos de funcionamiento y asignación de responsabilidades a clases y objetos. Esta patrón se conoce como el patrón de publicación-inscripción o modelo-patrón. Estos nombres sugieren la idea básicas del patrón, que son: el obejto de datos, que se le puede llamar Sujeto a partir de ahora, contiene atributos mediante los cuales cualquier objeto Observador o vista se puede subscribir a él pasándole una referencia a sí mismo. El sujeto mantiene así una lista de las referencias a sus observadores. Los observadores a su vez están obligados a implementar unos métodos determinados mediante los cuales el Sujeto es capaz de notificar a sus observadores suscritos los cambios que sufre para que todos ellos tengan la oportunidad de refrescar el contenido representado. De manera que cuando se produce un cambio en el Sujeto ejecutado, por ejemplo, por alguno de los observadores, el objeto de datos puede recorrer la lista de observadores avisando a cada uno. Este patrón suele observarse en los frameworks de interfaces gráficas orientados a objetos, en los que la forma de capturar los eventos es suscribir listeners a los objetos que pueden disparar eventos. El patrón Observer es la clave del patrón de arquitectura Modelo Vista Controlador(MVC).
Representación UML
Ejemplo
Supongamos que tenemos una clase Producto con un precio y queremos emitir un mensaje en la terminal cuando un producto cambie de precio. Para implementar este patrón Producto debería extender de Observable y otra clase hacer que implemente la interfaz Observer, sin embargo, si no queremos o no podemos hacer que nuestra clase extienda de Observable para no limitarnos en nuestra jerarquía de clases o porque ya extiende de otra podemos usar composición, por otro lado, si no queremos registrar el observador en cada instancia de Producto sino observar cualquier instancia que se cree podemos implementar el Observer de forma estática en la clase Producto. El observable ProductoObservable amplia la visibilidad del método setChanged para poder hacer uso de él usando compocisión, deberemos invocarlo para que los observadores sean notificados. Vamos a ver el código del siguiente ejemplo:
20. State: Permitir a un objeto modificar su modificamiento cuando su estado interno cambia. El objeto aparecerá para cambiar su clase. Las ventajas del patrón State son que localiza el comportamiento de un estado específico y divide el comportamiento para diferentes estado es decir el patrón State pone todo el comportamiento asociado con un estado particular en un objeto. Debido a que todo el código de un estado específico está en una subclase de State, los nuevos estados y transiciones pueden ser añadidos fácilmente añadiendo nuevas subclases. Hace las transiciones entre estados explícitas, es decir, cuando un objeto define su estado actual únicamente en términos de datos internos, sus transiciones no tienen una representación explícita. Introducir objetos separados para diferentes estados hace las transiciones más explícitas. Los objetos de los estados pueden ser compartidos, si los objetos de los estados no tienen variables instanciadas, el estado que representan está codificado completamente en su tipo, entonces el contexto puede compartir el objeto del estado. La clase Contexto define la interfaz de interés para los clientes. La clase State define una interfaz para encapsular el comportamiento asociado con un estado particular del contexto. Cada Clase ConcreteState implementa un comportamiento asociado con un estado del contexto.
Representación UML
Ejemplo
Pero para comprenderlo mejor veamos un sencillo ejemplo en el que controlamos el estado de un semáforo:
Semaforo.java (Contexto según el diagrama anterior):
EstadoSemaforo.java (Estado según el diagrama anterior):
EstadoVerde.java (un EstadoConcreto según el diagrama anterior):
EstadoNaranja.java (un EstadoConcreto según el diagrama anterior):
EstadoRojo.java(un EstadoConcreto según el diagrama anterior):
21. Strategy: Este patrón permite que el algoritmo a ejecutarse se seleccione en tiempo de ejecución. Este algoritmo proporciona una familia de algoritmos, encapsula cada uno dentro de un objeto y los hace intercambiables. Esto permite que el algoritmo a ejecutarse varíe en función del cliente que lo use. En primer lugar, es mucho más fácil comprender cada uno de los distintos comportamientos si su implementación está encapsulada en distintas clases, y no entrelazada en un único método. Esto permite de forma simple añadir nuevos comportamientos, y eliminar o modificar los existentes. En los casos en que existan varios objetos cuyo comportamiento sea practicamente el mismo, esto se puede reducir a una única clase que haga uso de distintas estrategias. Esto reduce el uso de subclases y, por tanto, el acoplamiento entre ellas. Las posibles estrategias se ejecutan dentro de un objeto de contexto que se encarga de recuperar la estrategia apropiada para el cliente. Cada una de las estrategias implementa una interfaz que define la firma del método de la estrategia.
Representación UML
Ejemplo:
Pese a que el ejemplo de nuestro videojuego es bastante ilustrativo, dado que en esta serie de artículos tenemos fijación por los coches, implementateremos el patrón a través de un hipotético módulo de la centralita del vehículo que nos permitirá alternar entre una conducción normal y deportiva. La diferencia entre ambas será simple: mayor consumo, mayor potencia, y mayor velocidad. Podríamos añadir más comportamiento "personalizados", como el endurecimiento de la suspensión, pero con estos dos elementos será suficiente para captar la idea.
Lo siguiente será crear el contexto. Esta clase será la encargada de establecer la conexión entre el cliente y las clases que implementan la estrategía, sustituyendo la clase que la implementa dependiendo del comportamiento esperado. Por lo tanto, se compondrá de una referencia a la interfaz que implementarán las estrategias más un método que permita cambiar de instancia(es decir, una property o un setter de toda la vida). A partir de esta funcionalidad básica, el contexto podrá realizar otras operaciones relacionadas con la estrategia que pretende modelar, como por ejemplo la invocación e sus métodos o la encapsulación del cambio de estrategia.
En realidad, la propia clase el cliente puede actuar como clase de contexto, pero siempre será mejor minimizar el acoplamiento entre las estrategias y las reglas de negocio. De este modo, respetaremos otro de los principios de la orientación a objetos: una clase, una responsabilidad. Para comprobar el funcionamiento de nuestro cliente, bastará con utilizar el siguiente código que hará uso del contexto para cambiar de estrategia en tiempo de ejecución.
Finalmente, el código que invoca a nuestro cliente, que será el siguiente:
No hay comentarios:
Publicar un comentario