design patterns · medium
GoF Observer — Publish-Subscribe State Notification
The Observer (Publish-Subscribe) pattern decouples a Subject from the objects that react to its state changes. The Subject maintains a list<Observer*>; any class can become an observer by implementing the Observer interface and calling subject.attach(this). When the Subject's state changes (e.g., setPrice()), it calls notify(), which iterates the observer list and calls update(this) on each. The PULL model passes the Subject pointer so each observer queries what it needs; the PUSH model includes data in the update() signature. Observers can be added/removed at runtime with zero changes to the Subject (OCP). Modern C++ often uses std::function<void(Subject*)> instead of a virtual Observer interface, or boost::signals2 for thread-safe broadcast.
Observer: Subject holds list<Observer*>; when state changes, notify() calls o->update(this) on each; observers attach/detach at runtime; Subject never knows concrete observer types — satisfies OCP.
The code
// Observer interfaceclass Observer {public: virtual void update(class Subject* s) = 0; virtual ~Observer() = default;};
// Subject (Publisher)class Stock : public Subject { int price_; std::list<Observer*> observers_;
public: void attach(Observer* o) { observers_.push_back(o); } void detach(Observer* o) { observers_.remove(o); } void notify() { for (auto* o : observers_) o->update(this); } void setPrice(int p) { price_ = p; notify(); } // triggers broadcast int getPrice() const { return price_; }};
// Concrete Observersclass Logger : public Observer { void update(Subject* s) override { auto* stock = static_cast<Stock*>(s); log("price=", stock->getPrice()); // PULL: queries subject }};class AlertSystem : public Observer { void update(Subject* s) override { /* check threshold */ }};
// Wiring — done at runtime, not compile timeStock msft;Logger logger;AlertSystem alerts;msft.attach(&logger);msft.attach(&alerts);msft.setPrice(58); // notifies ALL observers automaticallyWhat this lesson walks through
- 01The problem: subject with hard-coded listeners (anti-pattern)
- 02Observer pattern: subject only knows Observer* interface
- 03setPrice(58) — triggers notify() and broadcasts
- 04PULL model: observer queries the subject
- 05Attach/detach at runtime — add email observer
- 06Observer in C++ STL and real systems
Without Observer, the Subject (e.g., Stock) calls each listener directly. This violates SRP (Stock knows all consumers) and makes adding/removing listeners at runtime impossible. You must edit Stock every time you add a new consumer.
See it animated — step by step, at your own pace
Unlock the full interactive walkthrough of GoF Observer — Publish-Subscribe State Notification and 100+ animated C++ interview lessons.