What is Observer Pattern?
Observer pattern is a behavioral pattern that defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.
The object changes state is called Subject, and its dependents are called Observers.
When to use it?
You can use Observer pattern when you need one-to-many dependency between objects, the one will change its state and the many dependents need to keep track of those changes.
Problem
Let's say you are a big fan of NIKE, a famous shoes company. You want to get a new released product as much as possible, so everyday you visit company's website and check if there is new item.
What if the same thing happens in our application? A object needs to continuously check to get new information about other object's state by keeping executing something like getState()
method once in a minute or more frequently. However, obviously it is very inefficient since most of the time, getState()
returns the same values.
Solution
Let's assume we use SNS like X(Twitter) or Instagram, companies and people have their own account, and people can follow their favorite company so that people receive notification when the company post about new item or sale item. In this situation, Observer pattern is applicable.
ICompany (Subject Interface)
Provides interface for concrete company. It declares methods to register, deregister and notify account.Company (Subject)
WhensetSaleItem
method is called (the state is changed), we callsetItemChanged
method. Then,setItemChanged
method callsnotifyAccount
method. In this way, subject class notifies to observers whenever subject's state changes.
setSaleItem
(state change) ->setItemChanged
->notifyAccount
notifyAccount
method in Company class iterates eachfollower
and callupdate
method with its own Company object such asfollower.update(this)
IAccount (Observer Interface)
Provides interface for observers. This interface has one method declarationupdate()
to define observer's behavior when subject's state changes.Account (Observer)
Represents an account. Each account can follow/unfollow company's account. Followers can only receive notification.
Structure
Implementation in Java
public interface ICompany {
void registerAccount(IAccount account);
void removeAccount(IAccount account);
void notifyAccounts();
}
public class Company implements ICompany {
private List<IAccount> followers;
private String name;
private String saleItem;
public Company(String name) {
followers = new ArrayList<>();
this.name = name;
}
@Override
public void registerAccount(IAccount account) {
this.followers.add(account);
}
@Override
public void removeAccount(IAccount account) {
this.followers.remove(account);
}
@Override
public void notifyAccounts() {
for (IAccount follower : followers) {
follower.update(this);
}
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSaleItem() {
return saleItem;
}
public void setSaleItem(String saleItem) {
this.saleItem = saleItem;
saleItemChanged();
}
public void saleItemChanged() {
notifyAccounts();
}
}
public interface IAccount {
void update(Company company);
}
public class Account implements IAccount {
private String name;
public Account(String name) {
this.name = name;
}
@Override
public void update(Company company) {
System.out.println(this.name + " receives a new message from " + company.getName());
System.out.println("New sale item: " + company.getSaleItem());
}
}
public class Client {
public static void main(String[] args) {
Company nike = new Company("Nike"); // concrete subject
IAccount john = new Account("John");
IAccount david = new Account("David");
// John starts following Nike Inc.
nike.registerAccount(john);
nike.setSaleItem("Nike Zoom"); // Releases a new item
System.out.println("**********************");
// David becomes a new follower to Nike Inc.
nike.registerAccount(david);
nike.setSaleItem("Nike Air"); // Releases a new item
System.out.println("**********************");
// John doesn't receive message from Nike Inc. as he removes follow
nike.removeAccount(john);
nike.setSaleItem("Air Jordan");
}
}
Output:
John receives a new message from Nike
New sale item: Nike Zoom
**********************
John receives a new message from Nike
New sale item: Nike Air
David receives a new message from Nike
New sale item: Nike Air
**********************
David receives a new message from Nike
New sale item: Air Jordan
Pitfalls
- The order in which observers receive notification is random.
- notify() method can be costly as number of setter method that notifies state change in Subject and number of observers.
You can check all the design pattern implementations here.
GitHub Repository
P.S.
I'm new to write tech blog, if you have advice to improve my writing, or have any confusing point, please leave a comment!
Thank you for reading :)
Top comments (2)
Great overview of the Observer Pattern!
In which specific scenarios have you found the Observer Pattern to be most effective? Are there any common performance pitfalls developers should be cautious of when using this pattern in large-scale applications?
Write for us technology
Thank you for your review!
I took your advice into account and edited my blog.
I tried to write specific scenario in "Problem" section, and wrote about some of pitfalls as well.