About gof-observer
A skill explaining the Observer pattern for notifying multiple dependents when a subject changes. It helps developers model in-process updates while considering push versus pull notifications and common implementation pitfalls.
Key features
- 01Subject and observer roles
- 02Attach and detach lifecycle
- 03Push and pull notification styles
- 04Guidance on when to choose another approach
- 05Common Observer pitfalls
Use cases
- 01Keeping multiple views synchronized with state
- 02Notifying subscribers when an event occurs
- 03Decoupling a publisher from its dependents
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ yonatankarp/ software-design-skills --skill gof-observerAfter installing, type/gof-observerin Claude Code to confirm it loaded.
Details
From the project READMEOne-line summary
Define a one-to-many dependency: when one object (the subject) changes state, all its dependents (observers) are notified automatically — without the subject knowing their concrete types.
When to use this skill
- One object holds canonical state and several others must stay synchronized with it (data → multiple views, model → multiple listeners).
- Event-style coupling: "when X happens, do these N things, and the list of things grows over time".
- Decoupling a publisher from a set of subscribers that the publisher should not know about.
When NOT to use this skill
- Only one downstream consumer exists — a direct call is simpler.
- The "notification" must be synchronous and block the subject's progress until subscribers complete — Observer's typical implementation is push-style and assumes subscribers are independent.
- You need event sourcing, replay, or persistence — that's a real event bus / message broker, not the in-process Observer pattern.
Core content
The subject knows only a notify() method on an Observer interface. Concrete observers register and deregister via attach() / detach(). When the subject's state changes, it iterates its observer list and calls notify() on each.
Push vs pull:
- Push — subject passes the changed data into
notify(data). Simple; subjects know what observers want. - Pull — subject passes itself; observer queries back for the data it cares about. Looser coupling; observers pull only what they need.
Most modern frameworks (RxJava, Kotlin Flow, EventBus libraries, JavaFX bindings, even DOM event listeners) implement variants of Observer.
Decision heuristics
- If observers care about the same data, push is fine; if they care about different subsets of the subject's state, pull is better.
- Keep the observer interface narrow (one method) — fat observer interfaces become a maintenance burden.
- For more than a handful of subscribers or for cross-process coupling, reach for a real event bus (Kafka, RabbitMQ, Spring
ApplicationEventPublisher) rather than rolling Observer by hand.
Anti-patterns
- Memory leaks from observers that never deregister (the subject holds them alive forever) — make deregistration explicit and tested.
- Observers that mutate the subject during
notify()— causes re-entrancy bugs and observer-list invalidation. - Order-dependent observers — Observer guarantees notification, not order; if order matters, you need a different pattern.
See also
gof-command— when the "notification" needs to be queueable, undoable, or parameterized.gof-kotlin-idioms— in Kotlin,Flow,SharedFlow, andStateFloware first-class Observer-shaped primitives; rolling your own Observer is rarely warranted.
References
- Head First Design Patterns (2nd ed), Ch. 2 ("Keeping your Objects in the Know: the Observer Pattern") — the canonical chapter, framed around a weather monitoring station.