Seamless Updates: Navigating the Observer Pattern with Price Notifications and Beyond

Rishabh Gaud
System Weakness
Published in
4 min readDec 2, 2023

--

Ever wished you could magically receive a notification every time the price drops on that Amazon product? Well, enter the Observer Pattern — the unsung hero behind the scenes making sure you stay in the loop without refreshing your browser a million times.

Think of it as having your very own price-drop detective squad. Each member of the squad (observers) is silently watching the product, and when the price takes a dive, you get an instant notification. It’s like having a personal shopper who knows exactly when your dream item goes on sale.

source: Head First Design Patterns Book

Discover the Observer Pattern

Let’s take an different scenario to explore this pattern. Consider the functioning of newspaper or magazine subscriptions: A newspaper publisher establishes a business and commences the production of newspapers. You opt for a specific publisher, and each time a new edition is released, it is sent to you. As long as you maintain your subscription, you receive fresh newspapers. Cancellation occurs when you no longer desire the papers, leading to the cessation of deliveries. As long as the publisher is operational, individuals, hotels, airlines, and other entities frequently join and exit the newspaper subscribers’ list.

If you grasp the concept of newspaper subscriptions, you essentially comprehend the Observer Pattern, with the publisher termed the SUBJECT/OBSERVABLE and the subscribers referred to as the OBSERVERS.

Key Components of the Observer Pattern

Subject (or Observable): The object that maintains a list of observers and notifies them of any state changes.

Observer: The interface or abstract class that defines the update method. Concrete observer classes implement this method to react to changes in the subject.

Implementation of Observer Pattern

Let’s delve deeper into the Observer Pattern by getting our hands dirty with some code.

We will follow this folder structure for our app

  1. ObserverInterface.js
class ObserverInterface {
update(product) {
throw new Error('Method not implemented');
}
}

export default ObserverInterface;

2. ProductInterface.js

class ProductInterface {
setPrice(newPrice) {
throw new Error('Method not implemented');
}
}

export default ProductInterface;

3. Product.js

import ProductInterface from '../interfaces/ProductInterface.js';
import ObserverInterface from '../interfaces/ObserverInterface.js';

class Product extends ProductInterface {
constructor(name, price) {
super();
this.name = name;
this.price = price;
this.observers = [];
}

addObserver(observer) {
if (!(observer instanceof ObserverInterface)) {
throw new Error('Observer must implement the ObserverInterface.');
}
this.observers.push(observer);
}

removeObserver(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}

notifyObservers() {
this.observers.forEach(observer => {
observer.update(this);
});
}

setPrice(newPrice) {
this.price = newPrice;
this.notifyObservers();
}
}

export default Product;

4. Notification.js

import ObserverInterface from '../interfaces/ObserverInterface.js';

class Notification extends ObserverInterface {
update(product) {
console.log(`Notification: Price of ${product.name} has changed to $${product.price}`);
}
}

export default Notification;

5. main.js

import Product from './observables/Product.js';
import Notification from './observers/Notification.js';

const laptop = new Product('Laptop', 80000);
const Phone = new Product('Phone', 16000);

const user1 = new Notification();
const user2 = new Notification();

laptop.addObserver(user1);
laptop.addObserver(user2);
Phone.addObserver(user2);

laptop.setPrice(12000);

laptop.removeObserver(user2);

laptop.setPrice(1500);
Phone.setPrice(1000)

if we execute this main.js file then we can see our item price notification app done.

For running our app:

node main.js

Output:

Advantages of the Observer Pattern

  1. Flexibility: Easily add or remove observers without modifying the subject.
  2. Re-usability: Observers can be reused in different contexts.
  3. Decoupling: Subjects and observers are loosely coupled, promoting better code maintainability.

Conclusion

The Observer Pattern stands as a powerful tool for creating modular and maintainable systems, providing an elegant solution to scenarios where changes in one part of a system should trigger actions in other parts, all while maintaining a clean separation of concerns.

I am Rishabh Gaud, I work as a Software Developer, and really enjoy building Distributed Systems. Feel free to reach out to me on Linkedin or Portfolio for anything related to tech.

Happy learning 😃

Thank you for reading!. Let me know if you have any feedback or comments.

PS: here I attached the code as well Link

--

--

Software Engineer | Electronics and Communication Engineer | B.Tech @ NIT Srinagar