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.
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
Lets see the classes
- Subject – This is the object that is observed by the observers. If using the jdk framework this class generally extends the Observable class.
- 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.
- 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.
- Observer – Any type of object can be added as the observer, as long as it implements the observer interface.
- loose coupling between objects
- Implement a publish – subscribe scenario.
- Vary two class systems independently.
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.