Observer Pattern
“Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.”
Design Patterns: Elements of Reusable Object-Oriented Software
In the series of the Gang of Four design patterns, I wrote about the Command, Chain of Responsibility, Iterator, Mediator, Interpreter, and Memento patterns. These are part of the Behavioral pattern family that address responsibilities of objects in an application and how they communicate between them at runtime. In this post, I will look at using the Observer Pattern in Java. The Observer Pattern is a very common pattern. You may already be using it without knowing it!
Observer Pattern: Introduction
If you have done programming on messaging applications using JMS or GUI-based applications using Swing, you are likely aware of the publish-subscribe interaction model. In messaging applications, a publisher object publishes a message to a destination and subscriber objects that subscribe to the destination receive the message. Similarly in Swing, the whole concept of components having registered action listeners that fire up whenever the component’s state changes is based on the publish-subscribe model.
Even if you are not aware of the publish-subscribe model, don’t be anguished – It is very simple and intuitive. Consider this real life analogy of a magazine publisher that publishes magazines monthly. You, as a subscriber, subscribe to the publisher and you keep receiving a copy whenever a new edition of the magazine is published. At any time when you don’t want to receive the magazine anymore, you can unsubscribe, and the publisher stops sending you a copy.
Twitter is a great example of the Observer Pattern. You follow a user and when that user tweets, you along with all other followers of that user receive the tweet. Here, the user account you are following is the publisher and your twitter account along with the other followers are the subscribers. As with any other subscriber, when you unfollow the user, you stop receiving tweets of the user.
If you’ve understood the preceding scenarios involving publisher and subscriber, you are seeing the Observer Pattern. The only difference – In this pattern we will refer publisher as subject and subscriber as observer.
The Observer Pattern facilitates communication between decoupled objects. It defines relationship between objects – usually a single subject having a one-to-many relationship with multiple observers so that when the state of the subject changes, all its observers are notified accordingly. This figure illustrates what I just explained.
However, GoF doesn’t limit relationship between one subject with multiple registered observers. One observer can register itself with multiple subjects to receive notifications from them. Also, a subject can itself be an observer of another subject resulting in a chain of observers. However, this is not recommended as it can be the cause of debugging nightmares and result in memory leakage issues that Martin Flower very nicely explained here.
Participants of the Observer Pattern
To identify the participants of the Observer pattern, consider a scenario of an online auction application that enables registered users to bid on auctioned products. The application enables bidders to optionally opt to receive notifications through email or SMS whenever another bidder places a higher bid amount on a product. A bidder who is not interested in bidding on the product can opt out from receiving further notifications. Recalling the concepts covered till now, we can identify a product under auction as the subject (its state (price) will change when a new bid is placed). As there can be different products under auction, we will go ahead and declare the contract of defining products through an interface. Let’s name the interface Subject
. Let’s next model real products by creating a concrete class that implements Subject
. For this example, we will name the concrete class Product
.
Next, we will proceed to create the observers. For that, we will again create an interface, named Observer
. We will model real observers as objects of a Bidder
class that implements the Observer
interface.
Let’s now summarize the participants of the Observer pattern.
- Subject (
Subject
interface): Provides an interface to attach and detach Observer objects. - ConcreteSubject (
Product
class): Implements theSubject
interface. A ConcreteSubject sends notification toObserver
objects when its state change. - Observer (Observer interface): Provides an interface for objects that should be notified of changes in a
Subject
. - ConcreteObserver (
Bidder
class): ImplementsObserver
to receive notifications from theSubject
and keep its state consistent with the state of theSubject
.
Applying the Observer Pattern
Going ahead with the auction application, let’s start applying the Observer pattern by writing the Subject
interface and the Product
class.
Subject.java
package guru.springframework.gof.observer.observerimpl; import java.math.BigDecimal; public interface Subject { public void registerObserver(Observer observer); public void removeObserver(Observer observer); public void notifyObservers(); public void setBidAmount(Observer observer,BigDecimal newBidAmount); }
Product.java
package guru.springframework.gof.observer.observerimpl; import java.math.BigDecimal; import java.util.ArrayList; public class Product implements Subject{ private ArrayList<Observer> observers = new ArrayList<>(); private String productName; private BigDecimal bidAmount; private Observer observer; public Product(String productName, BigDecimal bidAmount){ this.productName=productName; this.bidAmount=bidAmount; } @Override public void setBidAmount(Observer observer,BigDecimal newBidAmount){ int res=bidAmount.compareTo(newBidAmount); if(res==-1){ this.observer=observer; this.bidAmount=newBidAmount; notifyObservers(); } else { System.out.println("New bid amount cannot be less or equal to current bid amount: "+this.bidAmount); } } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); System.out.println("-----------------"+observer+" has withdrawn from bidding----------------"); } @Override public void notifyObservers() { System.out.println("-----------------New bid placed----------------"); for (Observer ob : observers) { ob.update(this.observer,this.productName,this.bidAmount ); } } }
In the Subject
interface above, we declared four methods that the Product
class implements. In the overridden registerObserver()
and removeObserver()
methods of the Product
class, we added and removed the Observer
object passed to the methods to and from an ArrayList
respectively. In the overridden setBidAmount()
method, we assigned an Observer
object (that represents a bidder) and the bid amount to the instance variables declared in the class. At runtime, when this method gets called, the state of the Product
object changes. As the Product
object needs to notify all registered observers about the change, we called the notifyObservers()
method. In the notifyObservers()
method, we iterated through the registered Observer
objects stored in the ArrayList
. For each iteration, we called the update()
method on on the current Observer
object passing the changed state of the subject (Product
) and other information that the Observer
object requires. We can even pass values that cause the Observer
objects to react and rearrange their own state accordingly to be consistent with the new state of the subject.
Let’s next write the Observer
interface and the Bidder
class.
Observer.java
package guru.springframework.gof.observer.observerimpl; import java.math.BigDecimal; public interface Observer { public void update(Observer observer,String productName, BigDecimal bidAmount); }
Bidder.java
package guru.springframework.gof.observer.observerimpl; import java.math.BigDecimal; public class Bidder implements Observer{ String bidderName; public Bidder(String bidderName) { this.bidderName = bidderName; } @Override public void update(Observer observer,String productName, BigDecimal bidAmount){ if(observer.toString().equals(bidderName)){ System.out.println("Hello "+bidderName+"! New bid of amount "+bidAmount+" has been placed on "+productName+" by you"); } if(!observer.toString().equals(bidderName)) { System.out.println("Hello " + bidderName + "! New bid of amount " + bidAmount + " has been placed on " + productName + " by " + observer); } } @Override public String toString(){ return bidderName; } }
The Observer
interface that we wrote declares a single update()
method. For the sake of this example, we simply printed out the information about the changed state of the subject (Product
) in the overridden update()
method of the Bidder
class. In a real-world enterprise application, you might perhaps need to write code to send out emails to the bidder’s accounts or send SMS to them or perform any other functions that the requirements demand.
If you have noticed, the most important thing here is that the concrete Bidder
and Product
classes don’t have any reference to each other. This is powerful decoupling – an important programming practice that the SOLID design principles advocate. What it means is that if we later need to add another observer, say the auction manager who wants notifications of high value bidding on a product, we simply write a AuctionManager
class to implement the Observer
interface and register its object with the subject (Product
). The subject won’t require any modifications.
And how we achieved this? Recall the SOLID design principles that state “depend upon abstractions, not implementations”, which sums up Dependency Inversion principle. That is exactly what we did by writing the Subject
and Observer
interfaces.
Let’s write some test code to see the Observer pattern at work.
ObserverTest.java
package guru.springframework.gof.observer.observerimpl; import org.junit.Test; import java.math.BigDecimal; public class ObserverTest { @Test public void testObserver() throws Exception { Subject product=new Product("36 inch LED TV",new BigDecimal(350)); Observer bidder1=new Bidder("Alex Parker"); Observer bidder2=new Bidder("Henry Smith"); Observer bidder3=new Bidder("Mary Peterson"); product.registerObserver(bidder1); product.registerObserver(bidder2); product.registerObserver(bidder3); product.setBidAmount(bidder1, new BigDecimal(375)); product.removeObserver(bidder2); product.setBidAmount(bidder3, new BigDecimal(400)); } }
In the test code above, we created a new Product
object (subject) and three Bidder
objects (observers). Next, we made calls to the registerObserver()
method to register the observers with the subject. We then made a call to the setBidAmount()
method of the subject. This will result in a change of state of the subject and the registered observers will get the notification. We then unregistered a bidder and again made a call to the setBidAmount()
method to confirm that the unregistered bidder doesn’t receive notification this time. The output of the test is this.
------------------------------------------------------ T E S T S ------------------------------------------------------- Running guru.springframework.gof.observer.observerimpl.ObserverTest -----------------New bid placed---------------- Hello Alex Parker! New bid of amount 375 has been placed on 36 inch LED TV by you Hello Henry Smith! New bid of amount 375 has been placed on 36 inch LED TV by Alex Parker Hello Mary Peterson! New bid of amount 375 has been placed on 36 inch LED TV by Alex Parker -----------------Henry Smith has withdrawn from bidding---------------- -----------------New bid placed---------------- Hello Alex Parker! New bid of amount 400 has been placed on 36 inch LED TV by Mary Peterson Hello Mary Peterson! New bid of amount 400 has been placed on 36 inch LED TV by you Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.003 sec - in guru.springframework.gof.observer.observerimpl.ObserverTest
Observable Pattern in the Java API
Any discussion on the Observer pattern won’t be complete unless the Observable class and the Observer interface that Java provides out of the box for applying the Observer pattern are covered. Both the class and the interface are part of the java.util
package. You can subclass Observable
to represent a subject that observers wants to observe. Following is the modified Product
class of our auction application that now extends Observable
instead of our custom Subject
interface that we wrote earlier.
Product.java
package guru.springframework.gof.observer.javaapi; import java.util.Observable; import java.util.Observer; import java.math.BigDecimal; public class Product extends Observable{ private String productName; private BigDecimal bidAmount; private Observer observer; public Observer getObserver() { return observer; } public BigDecimal getBidAmount() { return bidAmount; } public String getProductName() { return productName; } public Product(String productName, BigDecimal bidAmount){ this.productName=productName; this.bidAmount=bidAmount; } public void setBidAmount(Observer observer,BigDecimal newBidAmount){ System.out.println("-----------------New bid placed----------------"); int res=bidAmount.compareTo(newBidAmount); if(res==-1){ this.observer=observer; this.bidAmount=newBidAmount; setChanged(); notifyObservers(); } else { System.out.println("New bid amount cannot be less or equal to current bid amount: "+this.bidAmount); } } }
As you can see the Product
class above now have lesser amount of code. Now, the Product
class doesn’t have the methods to register and remove observer objects; because by extending Observable
, Product
inherits the addObserver(Observer o)
and deleteObserver(Observer o)
methods of Observable
. Things also changed in the setBidAmount()
method. We now made calls to the setChanged()
and notifyObservers()
methods of the Observable
class. The setChanged()
method marks this Observable
object as having been changed while the notifyObservers()
method, as its name suggests, notifies all of its observers about the change. For the observers, we need to implement the Observer
interface that have a single update(Observable o, Object arg)
method. This method gets called whenever the subject (Product
) changes. Following is the modified Bidder
class implementing the Observer
interface.
Bidder.java
package guru.springframework.gof.observer.javaapi; import java.util.Observable; import java.util.Observer; public class Bidder implements Observer { Product observable; String bidderName; public Bidder(String bidderName) { this.bidderName = bidderName; } @Override public void update(Observable observable, Object arg){ this.observable = (Product) observable; String name = this.observable.getObserver().toString(); if(name.equals(bidderName)) { System.out.println("Hello "+bidderName+"! New bid of amount "+this.observable.getBidAmount()+" has been placed on "+this.observable.getProductName()+" by you"); } if (!name.equals(bidderName)) System.out.println("Hello "+bidderName+"! New bid of amount "+this.observable.getBidAmount()+" has been placed on "+this.observable.getProductName()+" by "+this.observable.getObserver()); } @Override public String toString() { return bidderName; } }
In the overridden update()
method of Bidder
, we again printed out the information about the changed state of the subject (Product
).
Let’s now write the test code.
ObservableJavaAPITest.java
package guru.springframework.gof.observer.javaapi; import org.junit.Test; import java.math.BigDecimal; public class ObservableJavaAPITest { @Test public void testObserver() throws Exception { Product product=new Product("L340 Digital Camera",new BigDecimal(325)); Bidder bidder1=new Bidder("Shally Ferguson"); Bidder bidder2=new Bidder("Dwayne Bravo"); Bidder bidder3=new Bidder("Craig Dawson"); product.addObserver(bidder1); product.addObserver(bidder2); product.addObserver(bidder3); product.setBidAmount(bidder1, new BigDecimal(350)); product.deleteObserver(bidder2); product.setBidAmount(bidder3, new BigDecimal(375)); } }
As you can see, the test code above is similar to the code we wrote earlier for our custom implementation but with a different set of data. Also, notice that instead of calling our custom registerObserver()
and removeObserver()
methods, here we made calls to the addObserver()
and deleteObserver()
methods of the Observable
class. The output on running the test is this.
------------------------------------------------------ T E S T S ------------------------------------------------------- Running guru.springframework.gof.observer.javaapi.ObservableJavaAPITest -----------------New bid placed---------------- Hello Craig Dawson! New bid of amount 350 has been placed on L340 Digital Camera by Shally Ferguson Hello Dwayne Bravo! New bid of amount 350 has been placed on L340 Digital Camera by Shally Ferguson Hello Shally Ferguson! New bid of amount 350 has been placed on L340 Digital Camera by you -----------------New bid placed---------------- Hello Craig Dawson! New bid of amount 375 has been placed on L340 Digital Camera by you Hello Shally Ferguson! New bid of amount 375 has been placed on L340 Digital Camera by Craig Dawson Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.158 sec - in guru.springframework.gof.observer.javaapi.ObservableJavaAPITest
Observer Pattern in the Spring Framework
In Spring, the Observer Pattern is used in the ApplicationContext's
event mechanism. The ApplicationEvent
class and ApplicationListener
interface of Spring enables event handling in Spring ApplicationContext
. When you deploy a bean that implements the ApplicationListener
interface, it will receive an ApplicationEvent
every time the ApplicationEvent
is published by an event publisher. Here, the event publisher is the subject and the bean that implements ApplicationListener
is the observer.
If you are creating your own custom event, your event publisher (subject) must implement the ApplicationEventPublisherAware
interface. This interface has a setter method named setApplicationEventPublisher()
that provides an ApplicationEventPublisher
object for using in your class. The subject can then publish an event by calling the publishEvent()
method of ApplicationEventPublisher
. The subject can publish any event that extends ApplicationEvent
and when the subject does so, the bean implementing ApplicationListener
(observer) receives the event. If you’re interested in creating custom events in Spring, I have a section on event publishing and consuming custom application events in my Spring Core online course.
Summary
In this post I have shown how to apply the Observer pattern with your own implementation and also using the in-built Observable
class and Observer
interface. So the natural question is – which approach should we use? I personally prefer my own implementation. The primary reason is, Observable
being a class, my subject after extending Observable
won’t be able to extend another class. Often, I find classes designed to be a subject already being part of an inheritance hierarchy. This out rightly prevents extending Observable
. In addition, I like to have more liberty on how my subject stores its observers. As, you can see in the example code, I used an ArrayList
– In fact I could have used any collection. But, by extending Observable
, my subject is forced to store observers in a Vector
because it is what Observable
internally uses. I am not trying to push any point that my ArrayList
implementation is better than the Vector
implementation of Observable
. But I can say that ArrayList
being faster than Vector
(because ArrayList
have no synchronization overhead like Vector
), my custom implementation will be the preferred choice in a performance critical application when synchronization is not an issue. Even if synchronization becomes a factor, I can always add the required synchronization code or even choose Vector
instead of ArrayList
. In short, writing your own implementation gives you flexibility. You just pay the cost of writing those extra lines of code.
At the end, irrespective of the implementation approach, the point is – During Enterprise Applications using the Spring Framework whenever you are in a situation where you have an object that needs to share its state with other objects, without knowing who those objects are, the Observer
pattern is exactly what you need.