Patrones de diseño de comportamiento: Observer

Intención del patrón

  • Define una dependencia uno a muchos entre objetos, para que, cuando un objeto cambie su estado, todos sus dependencias sean notificadas y actualizadas automáticamente.
  • Encapsula el componente central (o motor o núcleo) en un Subject abstracto y los componentes variables (o interfaz de usuario u opcional) en una jerarquía de Observer.
  • Es la parte "View" en Model-View-Controller.

Ejemplo de problema

Un diseño molítico de gran tamaño no se ajusta bien a una nueva representación gráfica o se imponen requerimientos de seguimiento.

Discusión

Define un objeto que es el Keeper (guardián) del modelo de datos y/o lógica de negocios (el Subject). Delega toda la funcionalidad visual a distintos y desacoplados objetos Observer. Los Observers se registran por sí mismos con el objeto Subject cuando es creado. Cada vez que Subject cambia, difunde a todos los objetos Observers registrados que ha cambiado y cada Observer consulta al objeto Subject por el subconjunto de datos del estado de Subject por el que es responsable monitorear.
Esto permite que el número y tipo de objetos View sean configurados dinámicamente en lugar de ser especificados estáticamente en tiempo de compilación.
El protocolo descripto más arriba especifica el modelo de interacción "Pull". En lugar de que Subject "pushing" (avise) a cada Observer que ha cambiado, cada Observer es responsable de obtener su particular "ventana de interés" de Subject. El modelo "Push" compromete la reutilización, mientras que el modelo "Pull" es menos eficiente.
Los temas que se discuten, pero que son dejados en consideración del diseñador, incluyen Implementación de compresión de eventos (sólo se envía una única difusión de cambio luego de que una serie de cambios consecutivos han ocurrido), teniendo un único Observer controlando múltiples Subjects y asegurándose que un Subject notifica a sus Observers cuando está a punto de desaparecer.
El patrón Observer captura la mayor parte de la arquitectura Model-View-Controller que ha sido una parte de la comunidad Smalltalk durante años.


Estructura



Subject representa la abstracción principal. Observer representa la abstracción variable. El Subject provoca que los objetos Observer realicen lo suyo. Cada Observer puede llamar nuevamente al Subject según sea necesario.


Ejemplo

El patrón Observer define una relación de uno a muchos, entonces, cuando un objeto cambia su estado, los otros son notificados y actualizados automáticamente. Algunas subastas presentan este patrón. Cada licitador posee una paleta numerada que es usada para indicar una oferta. El subastador comienza la subasta y "observa" cuando una paleta es levantada para aceptar la oferta. La aceptación de la misma cambia el precio máximo alcanzado y es avisado a todos los postores en la forma de una nueva oferta.




Check list


  1. Diferenciar entre la funcionalidad principal y la funcionalidad opcional.
  2. Modelar la funcionalidad independiente con una abstracción "Subject".
  3. Modelar la funcionalidad dependiente con una jerarquía "Observer".
  4. El Subject es acoplado sólo a la clase base Observer.
  5. El cliente configura el número y el tipo de Observers.
  6. Los Observers se registran por sí mismos con el Subject.
  7. El Subject transmite eventos para todos los Observers registrados.
  8. El Subject puede promocionar información a los Observers o, los Observers pueden extraer la información que necesita del Subject.


Reglas prácticas


  • Chain of responsability, Command, Mediator y Observer muestran cómo se pueden desacoplar emisores y receptores, pero con diferentes ventajas y desventajas. Chain of responsabilitypasa una solicitud del emisor a lo largo de una cadena de posibles receptores. Command normalmente especifica una conexión emisor-receptor con una clase derivada. Mediator tiene emisores y receptores con referencias cruzadas indirectamente. Observer define una interfaz totalmente desacoplada que permite a diferentes receptores ser configurados en tiempo de ejecución.
  • Mediator y Observer son patrones competidores. La diferencia entre ellos es que Observer distribuye la comunicación mediante la introducción de objetos "Observer" y "Subject", mientras que el objeto Mediator encapsula la comunicación entre otros objetos. Resulta más fácil hacer reutilizable objetos Observers y Subjects que hacer reusable un objeto Mediator.
  • Por otro lado, Mediator, puede aprovechar a Observer para registrar dinámicamente colegas y comunicarse con ellos.



Ejemplo de código en C#

using System;
using System.Collections;

class MainApp
{
  static void Main()
  {
    // Configure Observer pattern 
    ConcreteSubject s = new ConcreteSubject();

    s.Attach(new ConcreteObserver(s,"X"));
    s.Attach(new ConcreteObserver(s,"Y"));
    s.Attach(new ConcreteObserver(s,"Z"));

    // Change subject and notify observers 
    s.SubjectState = "ABC";
    s.Notify();

    // Wait for user 
    Console.Read();
  }
}

// "Subject" 
abstract class Subject
{
  private ArrayList observers = new ArrayList();

  public void Attach(Observer observer)
  {
    observers.Add(observer);
  }

  public void Detach(Observer observer)
  {
    observers.Remove(observer);
  }

  public void Notify()
  {
    foreach (Observer o in observers)
    {
      o.Update();
    }
  }
}

// "ConcreteSubject" 
class ConcreteSubject : Subject
{
  private string subjectState;

  // Property 
  public string SubjectState
  {
    get{ return subjectState; }
    set{ subjectState = value; }
  }
}

// "Observer" 
abstract class Observer
{
  public abstract void Update();
}

// "ConcreteObserver" 
class ConcreteObserver : Observer
{
  private string name;
  private string observerState;
  private ConcreteSubject subject;

  // Constructor 
  public ConcreteObserver(
    ConcreteSubject subject, string name)
  {
    this.subject = subject;
    this.name = name;
  }

  public override void Update()
  {
    observerState = subject.SubjectState;
    Console.WriteLine("Observer {0}'s new state is {1}",
      name, observerState);
  }

  // Property 
  public ConcreteSubject Subject
  {
    get { return subject; }
    set { subject = value; }
  }
}
Observer X's new state is ABC
Observer Y's new state is ABC
Observer Z's new state is ABC

0 comentarios:

Publicar un comentario

Muchas gracias por leer el post y comentarlo.

 
Copyright 2009 Programación SOLIDa
BloggerTheme by BloggerThemes | Design by 9thsphere