Design patterns are essential tools for building robust, maintainable, and scalable applications. Understanding and effectively utilizing design patterns can set you apart in frontend interviews. In this article, we will delve into the Observer Design Pattern, a powerful pattern that enables efficient communication between objects. This pattern is also known as the Publisher – Subscriber(Pub-Sub) pattern.
Observer Design Pattern
The Observer Pattern is a behavioural design pattern that defines a one-to-many dependency between objects. When one object (the subject) changes state, all its dependents (observers) are notified and updated automatically. This pattern is particularly useful for implementing distributed event-handling systems.
Implementing an Event Emitter in JavaScript is one of the most asked interview questions which uses the Observer Design Pattern.
class Subject {
constructor() {
this.observers = [];
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify(data) {
this.observers.forEach(observer => observer.update(data));
}
}
class Observer {
constructor(name) {
this.name = name;
}
update(data) {
console.log(`${this.name} received data: ${data}`);
}
}
const subject = new Subject();
const observer1 = new Observer('Observer 1');
const observer2 = new Observer('Observer 2');
subject.subscribe(observer1);
subject.subscribe(observer2);
subject.notify('Hello, Observers!'); // Output: Observer 1 received data: Hello, Observers!
// Observer 2 received data: Hello, Observers!
subject.unsubscribe(observer1);
subject.notify('Observer 1 has unsubscribed'); // Output: Observer 2 received data: Observer 1 has unsubscribedWhy is the Observer Pattern Important?
- Decoupling: The Observer Pattern decouples the subject from its observers, allowing changes in the subject to be automatically reflected in the observers without the subject needing to know the details of the observers.
- Scalability: This pattern allows adding new observers without modifying the subject, making it easy to scale and extend the system.
- Flexibility: Observers can be added or removed at runtime, providing flexibility in handling dynamic and changing requirements.
- Efficiency: By notifying only the relevant observers, the Observer Pattern ensures efficient communication and updates, reducing unnecessary processing.
Real-Time Example: Weather Station
class WeatherStation {
constructor() {
this.observers = [];
this.temperature = null;
}
subscribe(observer) {
this.observers.push(observer);
}
unsubscribe(observer) {
this.observers = this.observers.filter(obs => obs !== observer);
}
notify() {
this.observers.forEach((observer) => {
return observer.update(this.temperature));
}
}
setTemperature(temp) {
console.log(`Setting temperature to ${temp}`);
this.temperature = temp;
this.notify();
}
}
class TemperatureDisplay {
update(temp) {
console.log(`Temperature Display: ${temp} degrees`);
}
}
class Fan {
update(temp) {
if (temp > 25) {
console.log('Fan: It\'s hot, turning on...');
} else {
console.log('Fan: It\'s cool, turning off...');
}
}
}
const weatherStation = new WeatherStation();
const tempDisplay = new TemperatureDisplay();
const fan = new Fan();
weatherStation.subscribe(tempDisplay);
weatherStation.subscribe(fan);
weatherStation.setTemperature(20);
// Output: Setting temperature to 20
// Temperature Display: 20 degrees
// Fan: It's cool, turning off...
weatherStation.setTemperature(30);
// Output: Setting temperature to 30
// Temperature Display: 30 degrees
// Fan: It's hot, turning on...
Explanation of the Example
WeatherStation Class:
WeatherStationis the subject that maintains a list of observers and the current temperature.- The
subscribemethod adds an observer to the list. - The
unsubscribemethod removes an observer from the list. - The
notifymethod calls theupdatemethod on each observer with the current temperature. - The
setTemperaturemethod sets the temperature and notifies all observers.
Observer Classes:
TemperatureDisplayandFanare observer classes that implement theupdatemethod.- The
TemperatureDisplayclass simply logs the temperature. - The
Fanclass logs whether it is turning on or off based on the temperature.
Using the Observer Pattern:
- Instances of
TemperatureDisplayandFanare created and subscribed to theWeatherStation. - When the temperature is set using
setTemperature, all subscribed observers are notified and theirupdatemethods are called with the new temperature.
Importance in Real-World Applications
The Observer Pattern is widely used in real-world applications for implementing event-driven systems, such as GUIs, messaging systems, and real-time data feeds. It ensures that when an event occurs, all interested parties are notified and can react accordingly. By using the Observer Pattern, you can build more modular, flexible, and scalable applications.
