Where it fits
Use Observer when something happens in one place, and many other parts need to react.
Example: an order is paid. You may need to send an email, update inventory, create a receipt, and notify an admin dashboard.
One idea
The event source should not know every reaction. It should only publish an event to listeners that subscribed.
This keeps one change, like adding WhatsApp alerts later, from touching your payment code.
Common wrong refactor
Do not use Observer just because two files talk to each other. A direct function call is fine when there is only one clear receiver.
Observer helps when the list of reactions changes often, or when you want to add and remove reactions without editing the event source.
Before refactor
Here the payment service knows every side effect. Every new reaction makes this method longer.
class PaymentService {
pay(order) {
order.status = "PAID";
EmailService.sendReceipt(order.userEmail, order.id);
InventoryService.reduceStock(order.items);
AdminNotifier.notify("Order paid: " + order.id);
}
}After refactor
The payment service now publishes one event. Listeners handle their own work.
This example is plain JavaScript, so you can copy it into a small Node or frontend project.
class EventBus {
constructor() {
this.listeners = {};
}
subscribe(eventName, listener) {
if (!this.listeners[eventName]) this.listeners[eventName] = [];
this.listeners[eventName].push(listener);
}
unsubscribe(eventName, listener) {
this.listeners[eventName] = (this.listeners[eventName] || [])
.filter(item => item !== listener);
}
notify(eventName, data) {
(this.listeners[eventName] || []).forEach(listener => listener(data));
}
}
const eventBus = new EventBus();
eventBus.subscribe("order.paid", order => {
EmailService.sendReceipt(order.userEmail, order.id);
});
eventBus.subscribe("order.paid", order => {
InventoryService.reduceStock(order.items);
});
eventBus.subscribe("order.paid", order => {
AdminNotifier.notify("Order paid: " + order.id);
});
class PaymentService {
pay(order) {
order.status = "PAID";
eventBus.notify("order.paid", order);
}
}Check the boundary
Name events after facts that already happened, not commands. Use order.paid, not send.email.
This keeps listeners independent. One listener can send email, another can update stock, and the event name still makes sense.
Refactor safely
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done
Do this now
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done