Wednesday, February 9, 2011

Behavioral Patterns - Observer Pattern

Definition

One object changes state, all of its dependents are updated automatically. 


Intent

  • Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
  • Encapsulate the core (or common or engine) components in a Subject abstraction, and the variable (or optional or user interface) components in an Observer hierarchy.
  • The “View” part of Model-View-Controller.

Problem

A large monolithic design does not scale well as new graphing or monitoring requirements are levied.

Where to use & benefits

  • One change affects one or many objects.
  • Many object behavior depends on one object state.
  • Need broadcast communication.
  • AKA “Publish-Subscribe”.
  • Maintain consistency between objects
  • keep classes from becoming too tightly coupled, which would hamper reusability.
  • Related patterns include
    • Singleton, which is used to make observable object unique and accessible globally.
    • Mediator, which is used to encapsulate updated objects. 



    Motivation

    We can not talk about Object Oriented Programming without considering the state of the objects. After all object oriented programming is about objects and their interaction. The cases when certain objects need to be informed about the changes occured in other objects are frequent. To have a good design means to decouple as much as possible and to reduce the dependencies. The Observer Design Pattern can be used whenever a subject has to be observed by one or more observers.

    Let's assume we have a stock system which provides data for several types of client. We want to have a client implemented as a web based application but in near future we need to add clients for mobile devices, Palm or Pocket PC, or to have a system to notify the users with sms alerts. Now it's simple to see what we need from the observer pattern: we need to separate the subject(stocks server) from it's observers(client applications) in such a way that adding new observer will be transparent for the server.

    Intent

  • Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

Observer Design Pattern Implementation - UML Class Diagram

Implementation
The participants classes in this pattern are:
  • Observable - interface or abstract class defining the operations for attaching and de-attaching observers to the client. In the GOF book this class/interface is known as Subject.
  • ConcreteObservable - concrete Observable class. It maintain the state of the object and when a change in the state occurs it notifies the attached Observers.
  • Observer - interface or abstract class defining the operations to be used to notify this object.
  • ConcreteObserverA, ConcreteObserver2 - concrete Observer implementations.
The flow is simple: the main framework instantiate the ConcreteObservable object. Then it instantiate and attaches the concrete observers to it using the methods defined in the Observable interface. Each time the state of the subject it's changing it notifies all the attached Observers using the methods defined in the Observer interface. When a new Observer is added to the application, all we need to do is to instantiate it in the main framework and to add attach it to the Observable object. The classes already created will remain unchanged.


Applicability & Examples

The observer pattern is used when:
  • the change of a state in one object must be reflected in another object without keeping the objects tight coupled.
  • the framework we are writing needs to be enhanced in future with new observers with minimal changes.
Some Classical Examples:
  • Model View Controller Pattern - The observer pattern is used in the model view controller (MVC) architectural pattern. In MVC the this pattern is used to decouple the model from the view. View represents the Observer and the model is the Observable object.
  • Event management - This is one of the domains where the Observer patterns is extensively used. Swing and .Net are extensively using the Observer pattern for implementing the events mechanism.

Structure

Observer scheme
Subject represents the core (or independent or common or engine) abstraction. Observer represents the variable (or dependent or optional or user interface) abstraction. The Subject prompts the Observer objects to do their thing. Each Observer can call back to the Subject as needed.

Rules of thumb

  • Chain of Responsibility, Command, Mediator, and Observer, address how you can decouple senders and receivers, but with different trade-offs. Chain of Responsibility passes a sender request along a chain of potential receivers. Command normally specifies a sender-receiver connection with a subclass. Mediator has senders and receivers reference each other indirectly. Observer defines a very decoupled interface that allows for multiple receivers to be configured at run-time.
  • Mediator and Observer are competing patterns. The difference between them is that Observer distributes communication by introducing “observer” and “subject” objects, whereas a Mediator object encapsulates the communication between other objects. We’ve found it easier to make reusable Observers and Subjects than to make reusable Mediators.
  • On the other hand, Mediator can leverage Observer for dynamically registering colleagues and communicating with them.


Observer design pattern

  1. Model the “independent” functionality with a “subject” abstraction
  2. Model the “dependent” functionality with “observer” hierarchy
  3. The Subject is coupled only to the Observer base class
  4. Observers register themselves with the Subject
  5. The Subject broadcasts events to all registered Observers
  6. Observers “pull” the information they need from the Subject
  7. Client configures the number and type of Observers
abstract class Observer { 
protected Subject subj; 
  public abstract void update();
}

class HexObserver extends Observer { 
  public HexObserver( Subject s ) { 
    subj = s; 
    subj.attach( this ); 
  }

  public void update() { 
  System.out.print( " " + Integer.toHexString( subj.getState() ) ); 
  } 
} // Observers "pull" information 

class OctObserver extends Observer { 
  public OctObserver( Subject s ) {
    subj = s;
    subj.attach( this );
  } 
  public void update() {
    System.out.print( " " + Integer.toOctalString( subj.getState() ) );
  } 
} // Observers "pull" information 

class BinObserver extends Observer { 
  public BinObserver( Subject s ) { 
    subj = s; 
    subj.attach( this ); } // Observers register themselves 
    public void update() { 
    System.out.print( " " + Integer.toBinaryString( subj.getState() ) ); 
  } 
}

class Subject { 
  private Observer[] observers = new Observer[9];
  private int totalObs = 0;
  private int state;
  public void attach( Observer o ) {
    observers[totalObs++] = o;
  }

  public int getState() {
    return state;
  }
  
  public void setState( int in ) {
    state = in;
    notify();
  }

  private void notify() {
    for (int i=0; i < totalObs; i++) {
      observers[i].update();
    }
  }
}

public class ObserverDemo {
  public static void main( String[] args ) {
    Subject sub = new Subject();
    // Client configures the number and type of Observers
    new HexObserver( sub );
    new OctObserver( sub );
    new BinObserver( sub );
    Scanner scan = new Scanner();
    while (true) {
      System.out.print( "\nEnter a number: " );
      sub.setState( scan.nextInt() );
    }
  }
}
Enter a number: 15 f 17 1111 Enter a number: 17 11 21 10001 Enter a number: 31 1f 37 11111

No comments:

Post a Comment