Observer Pattern
The observer pattern is a widely used behavioral design pattern. It allows objects to subscribe and receive updates about events happening in the object they are observing.
Consider an example of an online clothing store. You want a specific hoodie, but it's currently out of stock. You check the site daily to see if it's available. The store offers alerts when the product is back in stock, so you subscribe to receive notifications. This eliminates the need to manually check the store.
Such problems are commonly solved using the observer pattern.
Observer pattern mainly has two things:
- An observable or a publisher
- An observer or a subscriber
In the example above, the observable is the product you're looking for and you are the observer.
The key concept behind the observable pattern is loose coupling, the observable and observer don’t need to know specifics of each other. In the above example, you have decoupled yourself from the process of manually checking the store every day, and the store only notifies you when there’s a relevant change.
Mental Model
Below is the mental model behind the observer pattern:
- Observable
- This is the object that is being observed.
- It maintains a list of observers.
- It provides methods to subscribe, unsubscribe, and notify observers.
- Observer
- This is the object that is interested in state changes of the observable.
- It subscribes to the observable to receive updates.
- It has an update method that is called by an observable when its state changes.
- There can be multiple observers.
Code Implementation
Let’s implement this in TypeScript using classes.
First, we will create an observable class called store
with the below interface,
interface Observable {
subscribe(o: Observer): void;
unsubscribe(o: Observer): void;
notify(): void;
}
The observable class will have a private message variable of type string and a setMessage
method to update the status of the product availability. It will also have an array to maintain a list of observers. Finally, let’s add subscribe
, unsubscribe
, and notify
methods.
Here’s the complete implementation of the observable,
class Store implements Observable {
private message: string = "";
private observers: Array<Observer> = [];
setMessage(message: string) {
this.message = message;
this.notify(); // notify all observers when the message state is changed
}
subscribe(o: Observer): void {
this.observers.push(o);
}
unsubscribe(o: Observer): void {
const index = this.observers.indexOf(o);
this.observers.splice(index, 1);
}
notify(): void {
for (const o of this.observers) {
o.update(this.message); // call update method of observer with new message
}
}
}
Now, let’s create an observer class called user
with the below interface,
interface Observer {
update(notice: string): void;
}
The observer class is going to be simple with only the update
method. Below is the complete implementation of an observer,
class User implements Observer {
private observable: Observable;
constructor(observable: Observable) {
this.observable = observable;
this.observable.subscribe(this); // subscribe automatically when a new User object is created
}
update(message: string): void {
console.log(`Store update : ${message}`);
}
}
Now when we update the store message using the setMessage
function it will notify all the observers of the class.
const store = new Store();
const user = new User(store); // after creation, it observes the store class
// store.subscribe(user) // Another way of subscribing to the observable
store.setMessage("Hoodie is available now"); // this will call the update method and console log the message
store.unsubscribe(user);
store.setMessage("Autumn sale is live now"); // this message won't be logged as user has unsubscribed from the observable
You can check the code in below replit:
Top comments (5)
Hi. Nice post!
There are couple of things I'd change so your implementation matches requirements a bit closer.
You mention a store and users that want to get notified of stock changes for a hoodie but code only shows the store implementation.
I'd expect to be able to subscribe to a product, not to a store directly.
And, unless I am mistaken, your implementation only allows a user to subscribe to one product (you're binding a user to one observable in the constructor).
I'd code it so you have a
store
with a list ofproducts
. Users can then subscribe to one or more products viaproduct.subscribe(user)
or,user.subscribe(product)
.user
'supdate
method would get aProduct
as argument so it knows what product has changed (name, quantity, price etc).Hope this helps!
I agree with your points. The current implementation indeed focuses on the store as the observable, but in a more realistic scenario, allowing users to subscribe to specific products makes a lot of sense. It provides a more fine-grained approach to notifications, and users should have the flexibility to choose the products they are interested in.
Thanks for taking the time to share your thoughts!
Please, write about Visitor!
Sure! Will do.
Thank you! Then I'll follow you and wait for it, my friend :3