Monday, January 22, 2007

Implementing Observer Pattern in Java

The Observer pattern allows an object (an Observer) to watch another object (a Subject). The subject and observer to have a publish/subscribe relationship. Observers can register to receive events from the Subject. When the subject can update the Observers when certain expected events occur. In Design Patterns, the Observer Pattern is defined as
Define a one-to-many dependency between objects so that when one object changes state,
all its dependents are notified and updated automatically.
The Observer pattern helps create a family of cooperating classes, while maintaining consistency and avoiding tight-coupling.
When To Use
  1. In a mailing list, where every time an event happens (a new product, a gathering, etc.) a message is sent to the people subscribed to the list.
  2. When a change to one object requires changing others, and you don't know how many objects need to be changed.
  3. When an object should be able to notify other objects without making assumptions about who these objects are (avoid tight-coupling).

Pros and Cons
  1. Loose coupling between Subject and Observer: The subject knows only a list of observers, that implement the Observer interface, it does no know the concrete implementation of the Observer.
  2. Broadcast communication: An event notification is broadcast observers irrespective of the number of Observers
  3. Unexpected updates: The can be blind to the cost of changing the subject.

Issues
  1. Mapping subjects to their observers: A subject can keep track it's observers as a list of all observer references or in a hash table, depending on whether space of time is the criteria respectively.
  2. Observing more than one subject: Using the Observer pattern you can implement a many-to-many relationship between subjects and observers. In this case, the Observer may need to know which subject is sending the notification. One way is to pass the Subject as an argument to the Update operation.
  3. Who triggers the update (Notify operation in Subject):
    • State setting operation in subject to trigger Notify.
    • Client trigger Notify at the right time.
  4. Dangling references to deleted subjects: Deleting a subject or a observer should not produce dangling references.
  5. Making sure subject state is self-consistent before notification: Otherwise, an observer can query subject's intermediate state through GetState operation.
  6. Avoiding observer-specific update protocols: push and pull models:
    • Push model: subject sends details change information to observer, for this the subject has to know about the Observers.
    • Pull model: subject sends minimum change information to observer and observer query for the rest of the information, as a result there might be more method calls that necessary.
  7. Specifying modifications of interest explicitly: One can register observer for only specific events. This can improve update efficiency.
The following is the UML diagram for the Observer Pattern
  • Subject: Maintains a list of Observer references. Subject also provides an interface for attaching and detaching Observer objects.
  • Observer: Defines an updating interface for objects that should be notified of changes in a subject.
  • ConcreteSubject: Stores state of interest to ConcreteObserver objects and sends notifications to its observers upon state changes.
  • ConcreteObserver: Maintains a reference to a ConcreteSubject object and a state that should stay consistent with the subject's.
The following piece of code shows how to implement Observer pattern in Java. In this example, the Subject notifies the Observers whenever it's state changes. Alternatively, we can have the client (the main method in this case) call notify on the Subject.
package patterns;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

interface Subject {
public void addObserver(Observer o);
public void removeObserver(Observer o);
public String getState();
public void setState(String state);
}

interface Observer {
public void update(Subject o);
}

class ObserverImpl implements Observer {
private String state = "";

public void update(Subject o) {
state = o.getState();
System.out.println("Update received from Subject, state changed to : " + state);
}
}

class SubjectImpl implements Subject {
private List observers = new ArrayList();

private String state = "";

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
notifyObservers();
}

public void addObserver(Observer o) {
observers.add(o);
}

public void removeObserver(Observer o) {
observers.remove(o);
}

public void notifyObservers() {
Iterator i = observers.iterator();
while (i.hasNext()) {
Observer o = (Observer) i.next();
o.update(this);
}
}
}

public class ObserverTest {

public static void main(String[] args) {
Observer o = new ObserverImpl();
Subject s = new SubjectImpl();
s.addObserver(o);
s.setState("New State");

}
}
ObserverTest.java

8 comments:

  1. Thanks a lot! Thats a nice example of observer pattern...

    ReplyDelete
  2. Good Article ... Keep It up

    And let me know how can I join the group.

    ReplyDelete
  3. Thanks a lot...That was nicely explained with the example...Although you could add another article about java.util.Observer and java.util.Observable to achieve the same purpose :-)

    ReplyDelete
  4. Thanks a lot. really very simple example and easy to understand.

    ReplyDelete

Popular Posts