lunes, 11 de febrero de 2013

Observer Pattern

  • Clasificación del patrón: de comportamiento.
  • Intención: definir una dependencia de uno-a-muchos con otros objetos, de forma que cuando un objeto cambia de estado todos sus dependientes son notificados y actualizados automáticamente.
  • También conocido como: Dependents, Publish-Subscribe.
  • Aplicabilidad: Se utiliza este patrón cuando se necesita
    • Cuando una abstracción tiene dos aspectos dependientes. Encapsular estos aspectos en objetos separados le permite variar y volver a utilizarlos de forma independiente.
    • Cuando un cambio en un objeto requiere cambiar a los demás, y no se sabe cuántos objetos necesitan ser cambiados.
    • Cuando un objeto debe ser capaz de notificar a otros objetos sin hacer suposiciones acerca de quién son estos objetos. En otras palabras, usted no quiere que estos objetos estrechamente acoplados.
  • Estructura:
  • Participantes
    • Subject: conoce a sus observadores. Cualquier número de objetos observador puede observar un sujeto. proporciona una interfaz para acoplar y desacoplar los objetos del observador.
    • Observador: define una interfaz de actualización para los objetos que deben ser notificados de los cambios en un sujeto.
    • ConcreteSubject: 
      • almacena su estado para los objetos ConcreteObserver
      • envía una notificación a sus observadores cuando su estado cambia.
    • ConcreteObserver: 
      • mantiene una referencia a un objeto de ConcreteSubject.
      • es el encargado de asignar un estado al ConcreteSubject. 
      • implementa la interface de actualización del Observer.
  • Colaboraciones
    • ConcreteSubject - ConcreteObservers: el primero notifica a sus observadores cada vez que ocurre un cambio en su estado, para que los observadores efectúen las operaciones correspondientes al nuevo estado, pudiendo consultar al Subject para conciliar su estado con el del sujeto.
  • Implementación
    • Asignación de sujetos a sus observadores. 
      • almacenar referencias a ellos explícitamente en el Subject. 
      • cuando hay muchos sujetos y pocos observadores, se puede negociar el espacio mediante el uso de una búsqueda asociativa (ej: una tabla hash) para mantener la asignación de sujeto a observador. Así, un sujeto sin observadores no incurre en gastos generales de almacenamiento, aunque aumenta el coste de acceso a los observadores.
    • Observando más de un Subject: podría tener sentido cuando un observador dependa de más de un sujeto, como podría ser el caso de una hoja de cálculo que dependa de más de una fuente de datos. El observador debe tener otra interfaz de actualización, para saber cuál de los dos lo invocó, o puede pasarsele el Subject por parámetro.
    • ¿Quién debe llamar a notify()? 
      • Tras cada cambio en Subject se llama a notify(). Esto libera a los clientes de tener que llamar a notify, pero causa una gran cantidad de Updates por cada pequeño cambio.
      • Que los clientes sean responsables de llamarlo. Esto permite llamar al método después de una serie de cambios sucesivos y evitar repetidas actualizaciones, pero la desventaja es que el cliente puede olvidar llamar a notify().
    • Cuando se elimina un Subject se debe avisar a los observadores de ello, para que eliminen su referencia a él. Borrar los observadores no es una buena solución, ya que pueden estar observando a otros Subject u Observers.
    • Asegurarse de que Subject sea consistente antes de llamar a notify().
    • Evitar update() específicos: 
      • Push model: el sujeto envía información detallada acerca del cambio a los observadores. Esto es ineficiente porque algunos observadores pueden no necesitar cierta información pasada
      • Pull model: el sujeto envía una notificación y los observadores deben pedir los detalles explícitamente al Subject. Esto es eficiente porque cada observer pide lo que necesita, pero ineficiente porque es difícil deducir qué cambió en el subject.
    • Hacer update() para observadores específicos. Se puede registrar los observadores sólo para eventos específicos. Cuando ocurre un evento, el sujeto informa sólo aquellos observadores que han registrado interés en ese evento.
    • ChangeManager para una actualización compleja: cuando el Subject y el Observer es compleja, se puede agregar un objeto intermediario. 
      • Vincula un sujeto con sus observadores.
      • Define una estrategia de actualización particular.
      • Actualiza todos los observadores dependientes cuando un sujeto lo requiere.
    • Combinación del Sujeto y los Observers: en lenguajes que carecen de herencia múltiple, como Smalltalk, generalmente no definen el Subject  y los Observers por separado, sino que combinan sus interfaces en una clase.
  • Consecuencias
    • El acoplamiento entre sujeto y observadores es abstracto y mínimo, por lo que los cambios en un sujeto o un observador no afectan al otro y se puede añadir nuevos observadores en cualquier momento.
    • Soporte para broadcast. Esto permite al Subject agregar y quitar observadores en cualquier momento, ya que todo depende del observador para manejar o hacer caso omiso de la notificación. 
    • Actualizaciones inesperadas, que provocan una cascada de cambios a los observadores y sus objetos dependientes. Además, el método update() no proporciona detalles sobre lo que ha cambiado en el Subject, de modo que los observadores pueden verse obligados a trabajar duro para deducir los cambios.
  • Motivación: Al dividir un sistema en un conjunto de clases cooperantes surge la necesidad de mantener coherencia entre los objetos relacionados, pero sin que estén estrechamente vinculados, porque eso reduce su reutilización.
  • Ejemplo:
  • Patrones relacionados
    • Mediator: el ChangeManager actúa como mediador entre los sujetos y observadores.
    • Singleton: el ChangeManager puede usar el patrón Singleton para ser único y accesible globalmente.

No hay comentarios:

Publicar un comentario en la entrada