Observer Pattern – Description and Example

The Observer pattern is such a popular design pattern that the jdk has provided a set of classes that make it easy to implement it. Here’s how we define the pattern :

An Observer pattern allows multiple objects to “observe” or “listen to” the changes in one object.

To explain the Observer pattern lets use an example. Imagine a property agent that rents out properties. Renters can subscribe to the property agent (could be a property renting site) and whenever a new property is listed all the renters who have subscribed to the agent will receive an email informing them of the new property. The renter could be an individual, a corporate entity or even another website. The property agent does not care who subscribes to its update as long as the subscriber implements the Observer interface.

Example
In the example below we have an agent class called PropertyAgent. The example shows two Renters – Renter and CorporateRenter. The property is described by the Property class. We will use the jdk Observable and Observer interfaces to implement the example.

The client creates the various objects. It also subscribes the renters (observers) to the property agent (Observable). The client demonstrates how when a new property is listed all the renters are informed.

public class Client {

	public static void main(String[] args) {
		PropertyAgent agent = new PropertyAgent();

		Renter renter1 = new Renter("renter1");
		agent.addObserver(renter1);

		CorporateRenter renter2 = new CorporateRenter("corpRenter2");
		agent.addObserver(renter2);

		Property property1 = new Property("house1", "2");
		agent.addProperties(property1);

		Property property2 = new Property("house2", "2");
		agent.addProperties(property2);
		
		agent.removeProperty(property1);
		agent.removeProperty(property2);

	}
}
						

The Property Agent has a list of properties and method to add and remove properties from that list. It needs to extend the Observable class. The Observable class maintains the list of observers and notifies them when a property is added or removed.

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;

public class PropertyAgent extends Observable {

	List<Property> properties = new ArrayList<>();

	public void addProperties(Property property) {
		properties.add(property);
		setChanged();
		notifyObservers(property);

	}

	public void removeProperty(Property property) {
		property.status = "removed";
		if (properties.remove(property))
			setChanged();
		notifyObservers(property);
	}
}
						
						

A retail renter is interested in notifications when a property agent adds or removes a property.

import java.util.Observable;
import java.util.Observer;

public class Renter implements Observer {

	String name;

	public Renter(String name) {
		this.name = name;
	}

	@Override
	public void update(Observable o, Object arg) {
		Property property = (Property) arg;
		System.out.println(name + " notified about " + property.status + " property " + property.name);
	}

}
						

A corporate renter is interested in notifications when a property agent adds or removes a property. Note that a renter and a corporate renter can have various other methods but as long as they both implement the observer interface, they can listen to notifications.

import java.util.Observable;
import java.util.Observer;

public class CorporateRenter implements Observer {

	String name;

	public CorporateRenter(String name) {
		this.name = name;
	}

	@Override
	public void update(Observable o, Object arg) {
		Property property = (Property) arg;
		System.out.println(
				"Corporate Renter " + name + " notified about " + property.status + " property " + property.name);
	}

}
						

The property that the renter is interested in.

public class Property {

	String name;
	String noOfBeds;
	String status;

	public Property(String name, String noOfBeds) {
		this.name = name;
		this.noOfBeds = noOfBeds;
		this.status = "added";
	}
}
				

Here’s a class diagram for the pattern

Observer Design Patterns

Lets see the classes

  1. Subject – This is the object that is observed by the observers. If using the jdk framework this class generally extends the Observable class.
  2. Observable – This class has methods to add or remove observers. Any object can be added to the list and the only requirement is that the object should implement the observer interface.
  3. Observer Interface – Any object that needs to observe has to implement this interace and implement the update method. This method is called by the Observable object (property agent) whenever it wants to inform of a change.
  4. Observer – Any type of object can be added as the observer, as long as it implements the observer interface.
Use the Observer pattern when you want

  • loose coupling between objects
  • Implement a publish – subscribe scenario.
  • Vary two class systems independently.

Use the observer pattern just for marking a change and not actually implementing one. For example if we plan to delete an object in the update method, it would be better to set the delete flag to true in the update method and use another method that checks for the flag and then performs the delete.

A subject can send minimal information in the notification and then let the observer ask for more information (pull) or the subject can send detailed information with the notification (push).

This finishes our tutorial on the observer pattern. It is a powerful pattern but should be used with caution since it may cause state changes without the client being aware of it.

Leave a Comment