Observer Design Pattern
It’s a behavioral design pattern, that enables a Subscriber/Observer
to register with Observable/Provider/Subject
in order to receive notifications whenever the state of the provider/subject changes.
- Terminology
- Observable/Provider/Subject - The data source which maintains a collection of subscribers and notifies them.
- Observer/Subscriber - These are the listeners that’ll get notified by Provider
A known use case for observer pattern is subscribing to blogs or newsletters to get notified whenever a new post is published.
One data source many subscribers.
Here is the UML diagram depicting the scenario.
Here is an example implementation of Observer design pattern.
public class BlogPost {
private String author;
private String title;
private String content;
public BlogPost(String author, String title, String content) {
this.author = author;
this.title = title;
this.content = content;
}
public String getAuthor() {
return author;
}
public String getTitle() {
return title;
}
public String getContent() {
return content;
}
@Override
public String toString() {
return "author=" + getAuthor() + ";" + "title=" + getTitle() + ";" + "content=" + getContent();
}
}
// Observable/subject/provider
public class Blog {
private BlogPost blogPost;
public void addBlogPost(BlogPost blogPost) {
this.blogPost = blogPost;
/*
* Assume the follwing logic in place
* 1. Call publish blog post
* 2. Post published confirmation
*/
notifySubscribers(blogPost);
}
private List<Subscriber> subscribers = new ArrayList<>();
public void addSubsriber(Subscriber subscriber) {
subscribers.add(subscriber);
}
public void removeSubscriber(Subscriber subscriber) {
subscribers.remove(subscriber);
}
private void notifySubscribers(BlogPost blogPost) {
for (Subscriber subscriber : subscribers) {
subscriber.update(blogPost);
}
}
}
// Observer/Subscriber
public interface Subscriber {
void update(Object value);
}
public class Subscriber1 implements Subscriber {
public void update(Object value) {
BlogPost blogPost = (BlogPost) value;
System.out.println("Subscriber1: Received new blog post notification: " + blogPost);
}
}
public class Subscriber2 implements Subscriber {
public void update(Object value) {
BlogPost blogPost = (BlogPost) value;
System.out.println("Subscriber2: Received new blog post notification: " + blogPost);
}
}
public class ProgramDriver {
public static void main(String[] args) {
// Many subscribers
Subscriber subscriber1 = new Subscriber1();
Subscriber subscriber2 = new Subscriber2();
// One Observable/Provider/Subject/DataSource
Blog blog = new Blog();
blog.addSubsriber(subscriber1); // Registers subscriber1
blog.addSubsriber(subscriber2); // Registers subscriber2
// Publishing a new BlogPost should notify suscbribers
BlogPost blogPost = new BlogPost("sairaghavak", "Observer Pattern", "....");
blog.addBlogPost(blogPost); // This triggers the notification
}
}
Another way to implement observer pattern using the Java beans API
java.beans.PropertyChangeEvent
java.beans.PropertyChangeListener
java.beans.PropertyChangeSupport
BlogPost
- Refer above snippet
// Observable/subject/provider
public class Blog {
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
private BlogPost blogPost;
public void addBlogPost(BlogPost newBlogPost) {
BlogPost oldBlogPost = this.blogPost;
this.blogPost = newBlogPost;
/*
* Assume the follwing logic in place
* 1. Call publish blog post
* 2. Post published confirmation
*/
this.pcs.firePropertyChange("blogPost", oldBlogPost, blogPost);
}
}
// Observer: Gets notified when a new post is created
public class Subscriber1 implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
BlogPost blogPost = (BlogPost) evt.getNewValue();
System.out.println("Subscriber1: Received new blog post notification: " + blogPost);
}
}
// Observer: Gets notified when a new post is created
public class Subscriber2 implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
BlogPost blogPost = (BlogPost) evt.getNewValue();
System.out.println("Subscriber2: Received new blog post notification: " + blogPost);
}
}
ProgramDriver
- Refer above snippet
Both the approaches to implement this pattern results in same output as shown below
Subscriber1: Received new blog post notification: author=sairaghavak;title=Observer Pattern;content=....
Subscriber2: Received new blog post notification: author=sairaghavak;title=Observer Pattern;content=....
References: