Skill: quochungto/bookforge-observer-pattern-implementor (version 1.0.0)

--- name: observer-pattern-implementor description: | Implement the Observer pattern to establish one-to-many dependencies where changing one object automatically notifies and updates all dependents. Use when a spreadsheet model needs to update multiple chart views, when UI components must react to data changes, when event systems need publish-subscribe, or when you need to decouple a subject from an unknown number of observers. Handles 10 implementation concerns including push vs pull models, dangling reference prevention, update cascade avoidance, and the ChangeManager compound pattern. version: 1.0.0 homepage: https://github.com/bookforge-ai/bookforge-skills/tree/main/books/design-patterns-gof/skills/observer-pattern-implementor metadata: {"openclaw":{"emoji":"📚","homepage":"https://github.com/bookforge-ai/bookforge-skills"}} status: draft depends-on: - design-pattern-selector - behavioral-pattern-selector source-books: - id: design-patterns-gof title: "Design Patterns: Elements of Reusable Object-Oriented Software" authors: ["Erich Gamma", "Richard Helm", "Ralph Johnson", "John Vlissides"] chapters: [5] pages: [273, 282] tags: [design-patterns, behavioral, gof, observer, publish-subscribe, event-system, mvc, change-manager, mediator, singleton] execution: tier: 2 mode: full inputs: - type: code description: "Existing code where one object's state changes need to propagate to dependents — tightly coupled notification logic, direct method calls between model and views, or a missing event/callback system" tools-required: [TodoWrite, Read, Write] tools-optional: [Grep, Glob] mcps-required: [] environment: "Requires a codebase or a sufficiently detailed design description. Code reading tools required to inspect existing structure before refactoring." --- # Observer Pattern Implementor ## When to Use A data source is directly calling update methods on its consumers, making it impossible to add or remove consumers without modifying the source. Apply this skill when: - An abstraction has two separable aspects — a subject (data) and observers (views/reactions) — and tightly coupling them limits reuse of each independently - A change to one object requires notifying an unknown or variable number of other objects, and you don't want to hard-code who those are - Objects should be able to notify others without making assumptions about who those objects are — you want zero coupling from subject to observer Do not apply if: - Only one consumer will ever exist and that is certain by design (direct call is simpler) - Observers trigger further changes that trigger more observers — cascade control is complex; use ChangeManager (Step 9) - The language/framework already provides this mechanism natively (e.g., React state, RxJS, Qt signals) — use those instead Before starting, verify you can answer: What is the subject (the thing that changes)? What are the observers (the things that react)? What state do observers need from the subject after a change? --- ## Process ### Step 1: Set Up Tracking and Audit Existing Coupling **ACTION:** Use `TodoWrite` to track progress, then read the codebase to map current subject-observer coupling. **WHY:** Observer refactoring touches at least three participants (Subject, ConcreteSubject, ConcreteObserver) and requires consistent interface changes across all of them. Without tracking, it is easy to partially refactor — adding the Observer interface while leaving direct calls in the subject — which produces a hybrid that is worse than either approach. The audit reveals whether existing coupling is simple (one direct call) or complex (multiple consumers with different update logic), which determines whether ChangeManager is needed. ``` TodoWrite: - [ ] Step 1: Audit existing coupling — map subjects and consumers - [ ] Step 2: Define Subject and Observer interfaces - [ ] Step 3: Implement ConcreteSubject with Attach/Detach/Notify - [ ] Step 4: Resolve trigger strategy (who calls Notify) - [ ] Step 5: Ensure state consistency before Notify - [ ] Step 6: Choose push vs pull model and implement Update - [ ] Step 7: Apply aspect-based registration if multiple event types - [ ] Step 8: Evaluate whether ChangeManager is needed - [ ] Step 9: Implement ChangeManager if warranted - [ ] Step 10: Wire up and verify — no dangling references ``` Use `Read` and `Grep` to answer: - Which class(es) change state and need to broadcast changes? (Subject candidates) - Which class(es) react to those changes? (Observer candidates) - How many consumers are there? Are they stable or do they change at runtime? - Are there multiple types of events, or one general "something changed" notification? --- ### Step 2: Define the Subject and Observer Interfaces **ACTION:** Create abstract `Subject` and `Observer` base classes (or interfaces). Do not write any concrete logic yet — define only the contracts. **WHY:** The power of Observer comes from the subject knowing only the abstract `Observer` interface — not any concrete observer type. If you skip this and call concrete methods directly, you recreate the coupling you're trying to eliminate. Defining the interfaces first forces you to commit to the notification contract before any implementation details leak in. **Subject interface** — three responsibilities: ```cpp class Subject { public: virtual ~Subject(); virtual void Attach(Observer*); // register a new observer virtual void Detach(Observer*); // deregister an observer virtual void Notify(); // broadcast change to all observers protected: Subject(); private: List<Observer*> _observers; // or a hash map — see Step 3 }; ``` **Observer interface** — one responsibility: ```cpp class Observer { public: virtual ~Observer(); virtual void Update(Subject* theChangedSubject) = 0; protected: Observer(); }; ``` Note: `Update` receives the subject pointer (not state data). This is the **pull model** default — observers call back on the subject for what they need. See Step 6 for the push vs pull decision. --- ### Step 3: Implement ConcreteSubject and the Observer List **ACTION:** Implement the concrete subject with state, state accessors (`GetState`/`SetState`), and a working `Notify`. Choose the storage strategy for the observer list. **WHY:** The naive approach — storing observers directly in every subject instance — works when subjects are few and observers are many per subject. When subjects are many and observers are few (e.g., many small model objects each observed by one dashboard), the per-subject list wastes memory. The hash map trade-off is real: choose based on the ratio of subjects to observers in your system. **Storage decision:** | Situation | Storage | Trade-off | |-----------|---------|-----------| | Few subjects, many observers each | `List<Observer*>` in Subject | Simple; O(1) attach; O(n) notify | | Many subjects, few observers each | External hash map (subject → observer list) | Eliminates per-subject overhead; increases access cost | **Standard Subject implementation:** ```cpp void Subject::Attach(Observer* o) { _observers->Append(o); } void Subject::Detach(Observer* o) { _observers->Remove(o); } void Subject::Notify() { ListIterator<Observer*> i(_observers); for (i.First(); !i.IsDone(); i.Next()) { i.CurrentItem()->Update(this); } } ``` **ConcreteSubject** adds only state and accessors: ```cpp class ConcreteSubject : public Subject { public: SubjectState GetState() const; void SetState(SubjectState s); private: SubjectState _subjectState; }; ``` --- ### Step 4: Decide Who Triggers Notify **ACTION:** Choose and implement one of two trigger strategies: automatic (subject triggers) or manual (client triggers). **WHY:** This is the most common source of Observer bugs. Automatic triggering ensures observers are never out of sync but fires notifications on every state mutation — including intermediate states in a multi-step update. Manual triggering gives the client control to batch multiple mutations before broadcasting, but adds an obligation: every code path that mutates state must remember to call `Notify`. Forgetting one call produces stale observers that are hard to debug. **Option A — Automatic trigger (subject calls Notify in SetState):** ```cpp void ConcreteSubject::SetState(SubjectState s) { _subjectState = s; Notify(); // automatic — client never calls Notify } ``` Use when: mutations are typically single-step, or missing a notification is worse than extra notifications. **Option B — Manual trigger (client calls Notify):** ```cpp // Client code subject->SetState(s1); subject->SetBoundary(b); // multiple mutations subject->Notify(); // one notification for both changes ``` Use when: performance matters and multiple state changes should batch into one notification round. **Recommendation:** Default to Option A. Switch to Option B only if profiling shows notification overhead is significant, or if the use case explicitly requires batching (e.g., multi-step transaction commit). --- ### Step 5: Ensure Subject State Is Self-Consistent Before Notify **ACTION:** Audit every operation that calls `Notify` (directly or via `SetState`) and verify that all subject state is fully updated before `Notify` fires. **WHY:** Observers call `GetState` on the subject inside their `Update` method to synchronize. If `Notify` fires while the subject is in a partially-updated state — for example, after a base class operation but before a subclass operation completes — observers will read inconsistent data and enter an inconsistent state of their own. This is a silent bug: observers receive a valid-looking notification but pull stale or partial data. **Common violation in inheritance:** ```cpp // WRONG — notification fires before subclass state is updated void MySubject::Operation(int newValue) { BaseClassSubject::Operation(newValue); // triggers Notify here _myInstVar += newValue; // too late — observers already ran } ``` **Fix — use Template Method to control notification timing:** ```cpp // In abstract Subject — Notify is last void Text::Cut(TextRange r) { ReplaceRange(r); // redefined in subclasses — all state updated here Notify(); // fires only after the complete operation } ``` Always ensure `Notify` is the **last operation** in any state-mutating method. Document which operations trigger notifications in the class interface comment. --- ### Step 6: Choose and Implement the Push or Pull Model **ACTION:** Decide whether the subject sends state data to observers (push) or observers query the subject (pull). Implement `Update` accordingly. **WHY:** This is the core design trade-off for observer usability versus coupling. The pull model makes the subject maximally ignorant of its observers (it sends no assumptions about what they need), but can be inefficient — each observer must figure out what changed on its own. The push model is efficient for observers with narrow needs but makes the subject assume it knows what observers care about, reducing reusability when different observers need different data. **Pull model** — subject sends only its identity; observers pull what they need: ```cpp void DigitalClock::Update(Subject* theChangedSubject) { if (theChangedSubject == _subject) { // guard: verify it's the right subject int hour = _subject->GetHour(); int minute = _subject->GetMinute(); Draw(); // re-render with pulled values } } ``` **Push model** — subject sends relevant state as Update arguments: ```cpp // Subject void Subject::Notify(int newValue) { for each observer: observer->Update(this, newValue); } // Observer virtual void Update(Subject*, int newValue) = 0; ``` **Decision:** | Prefer pull when... | Prefer push when... | |--------------------|---------------------| | Different observers need different parts of subject state | All observers need the same data | | Subject does not know what observers care about | The changed data is cheap to pass and expensive to re-query | | Maximum observer reusability is important | Observer should not need to hold a reference to the subject | Pull is the default. Push reduces reusability because it encodes assumptions about observer needs into the Subject interface. --- ### Step 7: Apply Aspect-Based Registration for Multiple Event Types **ACTION:** If the subject produces multiple distinct event types and observers care about only some, extend `Attach` to accept an "aspect" (event category) parameter. **WHY:** Without aspect filtering, every observer is notified of every change — even changes it does not care about. This wastes cycles and can cause incorrect behavior if an observer's `Update` logic assumes it is only called for its relevant event. Aspect-based registration lets observers declare their interest at subscription time, so `Notify` only calls the relevant observers. **Extended interfaces:** ```cpp // Subject registration with aspect void Subject::Attach(Observer* o, Aspect& interest); // Observer Update with aspect parameter void Observer::Update(Subject* s, Aspect& interest); ``` **Notify implementation with aspect filtering:** ```cpp void Subject::Notify(Aspect& changedAspect) { // only notify observers registered for this aspect for each (observer, registeredAspect) in _observerMap: if registeredAspect == changedAspect: observer->Update(this, changedAspect); } ``` Use when: subjects produce heterogeneous events (e.g., a document that can have text changes, layout changes, and selection changes), and observers specialize in only one type. --- ### Step 8: Evaluate Whether ChangeManager Is Needed **ACTION:** Assess whether the subject-observer dependency graph is simple or complex. If complex, implement ChangeManager (Step 9). If simple, skip Step 9. **WHY:** The standard Notify-loop works well when subjects and observers are independent. It breaks down in two scenarios: (1) a single operation modifies multiple interdependent subjects, causing observers to be notified multiple times for what is logically one change; (2) observers themselves observe multiple subjects, creating diamond-shaped dependency graphs where redundant updates proliferate. ChangeManager exists to handle these cases — it absorbs the complexity so subjects and observers don't have to. **Use ChangeManager if any of the following are true:** - One high-level operation modifies two or more subjects whose observers overlap - Any observer observes more than one subject (creating potential for redundant updates) - Notification order matters and must be controlled globally - You need a specific update strategy (e.g., "update all after all subjects have changed") **If none of the above apply:** ChangeManager adds complexity for no benefit. Keep the simple direct Notify loop from Step 3. --- ### Step 9: Implement ChangeManager (Observer + Mediator + Singleton) **ACTION:** If Step 8 determined ChangeManager is needed, implement it as a mediator that owns the subject-observer mapping, controls update strategy, and exists as a singleton. **WHY:** ChangeManager combines three patterns with a specific purpose: it acts as a **Mediator** (centralizing the subject-observer communication logic), uses the **Observer** protocol (subjects and observers still implement the same interfaces), and is a **Singleton** (there is exactly one ChangeManager per subsystem — subjects and observers both need to find the same instance). This combination eliminates redundant updates when multiple subjects change in one operation, and allows the update strategy to be changed without touching Subject or Observer classes. **ChangeManager responsibilities:** 1. Maintains the subject-to-observer mapping (replaces per-subject observer lists) 2. Defines the update strategy — when and in what order observers are notified 3. Updates all dependent observers when a subject requests it **Two built-in strategies:** | Strategy | Behavior | Use when | |----------|----------|----------| | `SimpleChangeManager` | For each subject, notify all its observers immediately | Observers observe only one subject; no redundant update risk | | `DAGChangeManager` | Mark all affected observers; update each marked observer exactly once | Observers observe multiple subjects (directed acyclic graph dependencies) | **ChangeManager interface:** ```cpp class ChangeManager { public: static ChangeManager* Instance(); // Singleton access virtual void Register(Subject*, Observer*); virtual void Unregister(Subject*, Observer*); virtual void Notify() = 0; // strategy-defined update dispatch protected: ChangeManager(); private: static ChangeManager* _instance; }; ``` **Subject delegates to ChangeManager:** ```cpp // Subject no longer stores observer list — delegates to ChangeManager void Subject::Attach(Observer* o) { ChangeManager::Instance()->Register(this, o); } void Subject::Notify() { ChangeManager::Instance()->Notify(); } ``` **DAGChangeManager Notify — prevents redundant updates:** ```cpp void DAGChangeManager::Notify() { // Pass 1: mark all observers that need updating for each subject s in _subjects: for each observer o of s: mark o as pending // Pass 2: update each marked observer exactly once for each marked observer o: o->Update(relevantSubject); unmark o; } ``` --- ### Step 10: Wire Up and Prevent Dangling References **ACTION:** Wire all observers to their subjects via `Attach`. Add lifecycle management to prevent dangling references when subjects are deleted. Verify the full notification chain manually or with a test. **WHY:** Deleting a subject that observers still hold a reference to produces dangling pointers — observers will attempt to call `GetState` on freed memory. Simply deleting the observers is not a valid solution because they may be observing other subjects or be referenced by other objects. The subject must notify observers of its own deletion so they can nullify their references. **Deletion protocol in subject destructor:** ```cpp Subject::~Subject() { // Notify observers that this subject is going away // so they can reset their stored reference ListIterator<Observer*> i(_observers); for (i.First(); !i.IsDone(); i.Next()) { i.CurrentItem()->SubjectDeleted(this); } } // Observer handles deletion void ConcreteObserver::SubjectDeleted(Subject* s) { if (s == _subject) { _subject = nullptr; // nullify — do not delete } } ``` **Wiring example:** ```cpp ClockTimer* timer = new ClockTimer; DigitalClock* digitalClock = new DigitalClock(timer); // Attach in constructor AnalogClock* analogClock = new AnalogClock(timer); // Attach in constructor // When timer ticks, both clocks update automatically ``` **Verification checklist:** - [ ] Attach is called before any state changes that should be observed - [ ] Detach is called in every observer destructor - [ ] Deleting a subject does not crash observers - [ ] Adding a new observer at runtime receives subsequent updates correctly - [ ] Notifications fire only when subject state is fully consistent (Step 5) --- ## Pitfalls **1. Cascade updates.** Observer A's `Update` changes subject B, which notifies observer C, which changes subject D... This is the most serious Observer failure mode, and it is difficult to detect because it appears during runtime. Prevention: avoid state changes inside `Update` that would notify other observers. If cascade is unavoidable, use `DAGChangeManager` to ensure each observer updates exactly once per logical change. **2. Dangling references to deleted subjects.** Deleting a subject without notifying observers leaves them with stale pointers. The crash appears on the next notification cycle, not at the point of deletion, making it hard to locate. Prevention: always implement the deletion-notification protocol in Step 10. **3. Inconsistent state notification.** Calling `Notify` before all subject state is updated (typically in inherited operations — see Step 5). Observers run during `Update` and pull stale data. Prevention: always use Template Method to put `Notify` last, and audit inheritance chains for calls to `super.Operation()` that trigger notifications mid-update. **4. Trigger ambiguity.** Mixing automatic and manual trigger strategies across different subjects in the same system. Developers expect one behavior and get the other; observers are sometimes notified twice, sometimes not at all. Prevention: pick one strategy and apply it uniformly across the system. Document it in the Subject class comment. **5. Push overspecification.** The push model embeds assumptions about what observers need directly into the Subject's `Notify` signature. When observer needs diverge (one needs the full new state, another only needs a delta, a third only needs to know that *something* changed), the push signature becomes a compromise that serves none of them well. Prevention: default to pull. Only add push parameters that are universally needed by all observers, and only after profiling shows that the extra pull calls are a measurable cost. --- ## Examples ### Example 1: Spreadsheet Model with Multiple Chart Views **Scenario:** A spreadsheet has a data model that three chart widgets (bar chart, pie chart, line chart) read directly. Currently the model calls `barChart.refresh()`, `pieChart.refresh()`, and `lineChart.refresh()` in its `SetCell` method. Adding a fourth chart requires modifying the model. **Trigger:** "Every new chart type requires touching the spreadsheet model." **Process:** - Step 1: Audit reveals `SpreadsheetModel` directly references three concrete chart classes - Step 2: `SpreadsheetModel` becomes `ConcreteSubject`; each chart implements `Observer` - Step 3: `List<Observer*>` in Subject (few subjects, multiple observers) - Step 4: Automatic trigger — `SetCell` calls `Notify()` after updating data - Step 5: `Notify` is last in `SetCell` — state is fully updated first - Step 6: Pull model — charts call `GetCellValue(row, col)` in their `Update` - Step 8: No complex dependencies — skip ChangeManager **Output:** `SpreadsheetModel` has no reference to any chart class. New charts attach themselves; model never changes. --- ### Example 2: Clock with Multiple Display Observers **Scenario:** A `ClockTimer` (concrete subject) notifies time displays. A `DigitalClock` and `AnalogClock` both observe the same timer. This is the canonical sample from the GoF text. **Trigger:** "Both clock displays must always show the same time, but neither should know about the other." **Key implementation details:** - `DigitalClock` inherits from both `Widget` (UI toolkit) and `Observer` (combining concern 10 — Subject/Observer in one class hierarchy via multiple inheritance) - Constructor calls `_subject->Attach(this)`; destructor calls `_subject->Detach(this)` — full lifecycle management - `Update` guards on subject identity: `if (theChangedSubject == _subject)` — handles potential future case of observing multiple subjects ```cpp void DigitalClock::Update(Subject* theChangedSubject) { if (theChangedSubject == _subject) { Draw(); } } void DigitalClock::Draw() { int hour = _subject->GetHour(); int minute = _subject->GetMinute(); // render digital display } ``` **Output:** `ClockTimer::Tick()` calls `Notify()`; both displays update independently without knowing each other exist. --- ### Example 3: Multi-Subject Dashboard with ChangeManager **Scenario:** A financial dashboard has three data subjects: `PriceSubject`, `VolumeSubject`, and `PositionSubject`. A `RiskSummaryObserver` observes all three. When a trade executes, all three subjects change in one operation. Without ChangeManager, `RiskSummaryObserver.Update` fires three times for one logical event. **Trigger:** "Our risk view recalculates three times per trade because it observes three subjects." **Process:** - Step 8: Observer observes multiple subjects — DAG dependency. ChangeManager required. - Step 9: Implement `DAGChangeManager`. Each subject calls `ChangeManager::Instance()->Notify()`. DAGChangeManager marks `RiskSummaryObserver` when `PriceSubject` changes, marks it again when `VolumeSubject` changes (already marked — no-op), then updates it once. **Output:** One trade → three subject changes → `RiskSummaryObserver.Update` called exactly once. --- ## Reference Files | File | Contents | |------|----------| | `references/observer-implementation-guide.md` | All 10 implementation concerns in full detail, ChangeManager class diagrams, push/pull protocol variants, aspect-based registration patterns, and language-specific notes | ## License This skill is licensed under [CC-BY-SA-4.0](https://creativecommons.org/licenses/by-sa/4.0/). Source: [BookForge](https://github.com/bookforge-ai/bookforge-skills) — Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides. ## Related BookForge Skills Install related skills from ClawhHub: - `clawhub install bookforge-design-pattern-selector` - `clawhub install bookforge-behavioral-pattern-selector` Or install the full book set from GitHub: [bookforge-skills](https://github.com/bookforge-ai/bookforge-skills)

path: references/observer-implementation-guide.md
content: # Observer Pattern — Complete Implementation Guide

Source: Design Patterns: Elements of Reusable Object-Oriented Software (GoF), pages 273–282.

---

## The 10 Implementation Concerns

### 1. Mapping Subjects to Their Observers

The simplest approach is for a subject to store references to its observers directly in a `List<Observer*>`. This incurs storage overhead per subject instance regardless of how many observers are registered.

When subjects outnumber observers significantly — for example, many small model objects each observed by one centralized view — the per-instance list wastes memory for the common case of zero or one observer.

**Alternative:** Use an external associative structure (hash table, dictionary) that maps subjects to their observer lists. This trades per-instance storage overhead for a small increase in lookup cost. The hash table approach is global — it centralizes all subject-observer mappings outside the subjects themselves.

```
// Conceptual: external mapping
Map<Subject*, List<Observer*>*> observerMap;

// Attach
observerMap[subject]->Append(observer);

// Notify (subject-side)
observerMap[this]->ForEach(o => o->Update(this));
```

This approach also makes it possible to answer "which subjects does observer O observe?" — the reverse mapping — which the in-subject list approach cannot answer efficiently.

---

### 2. Observing More Than One Subject

An observer may legitimately depend on more than one subject. A spreadsheet cell that aggregates two data streams, or a dashboard panel that shows a composite of price and volume data, is observing multiple subjects.

The basic `Update()` signature does not tell the observer which subject triggered the notification. The observer must be able to discriminate.

**Solution:** Pass the subject itself as a parameter to `Update`. The observer compares the received pointer against its stored subject references:

```cpp
void CompositeObserver::Update(Subject* theChangedSubject) {
    if (theChangedSubject == _priceSubject) {
        // handle price change
    } else if (theChangedSubject == _volumeSubject) {
        // handle volume change
    }
}
```

This is why the GoF base Observer interface uses `Update(Subject*)` rather than a parameterless `Update()`.

---

### 3. Who Triggers the Update

There are exactly two options, and each has a failure mode.

**Option A — Subject triggers automatically (SetState calls Notify)**

```cpp
void Subject::SetState(State s) {
    _state = s;
    Notify();
}
```

- Advantage: Clients never forget to trigger. Observers are always in sync.
- Disadvantage: If a client calls `SetA()`, then `SetB()`, then `SetC()`, three separate notification rounds fire for what is logically one composite change. Each intermediate state triggers observer updates, which may be incorrect or wasteful.

**Option B — Client triggers manually**

```cpp
subject->SetA(...);
subject->SetB(...);
subject->SetC(...);
subject->Notify();  // one round for all three changes
```

- Advantage: Batching is explicit. One notification per logical operation.
- Disadvantage: Every code path that mutates state must remember to call `Notify`. Missing one call silently leaves observers stale. This is a correctness hazard.

**Recommendation:** Default to Option A. Move to Option B only when profiling reveals notification overhead is a measurable cost, or when a use case genuinely requires atomic multi-step state changes (e.g., a transaction commit that sets multiple fields before broadcasting).

---

### 4. Dangling References to Deleted Subjects

When a subject is deleted, observers may still hold pointers to it. On the next notification cycle — or when any observer attempts to call `GetState` — the program accesses freed memory. The crash appears after the deletion, not at it, making the bug hard to locate.

**Wrong approach:** Deleting the observers when the subject is deleted. Observers may be registered with multiple subjects, or referenced by other objects. Deleting them unilaterally is incorrect.

**Correct approach:** The subject notifies its observers of its own deletion so each observer can nullify its stored reference:

```cpp
Subject::~Subject() {
    ListIterator<Observer*> i(_observers);
    for (i.First(); !i.IsDone(); i.Next()) {
        i.CurrentItem()->SubjectDeleted(this);
    }
}

void Observer::SubjectDeleted(Subject* s) {
    // Default: no-op. Subclasses override if they store the subject.
}

void ConcreteObserver::SubjectDeleted(Subject* s) {
    if (s == _subject) {
        _subject = nullptr;  // nullify — observer still exists, subject is gone
    }
}
```

Observers must guard `_subject != nullptr` before using it in `Update`.

---

### 5. Making Sure Subject State Is Self-Consistent Before Notification

Observers call `GetState` on the subject inside `Update`. If `Notify` fires while the subject is partially updated, observers will read a mix of old and new state.

This most commonly occurs in inheritance chains where a subclass operation calls an inherited operation that triggers `Notify`, then continues updating subclass-specific state:

```cpp
// VIOLATION — notification fires at BaseClassSubject::Operation,
// before _myInstVar is updated
void MySubject::Operation(int newValue) {
    BaseClassSubject::Operation(newValue);  // Notify fires here via SetState
    _myInstVar += newValue;                 // already too late
}
```

**Fix using Template Method:** Define an abstract primitive for subclasses to override, and put `Notify` at the end of the template method in the base class:

```cpp
// Base class controls notification timing
void Subject::DoOperation(int newValue) {
    SetInternalState(newValue);     // calls subclass override — all state updated
    Notify();                       // fires only when self-consistent
}

// Subclass — overrides the primitive, not the template method
void MySubject::SetInternalState(int newValue) {
    BaseClassSubject::SetInternalState(newValue);
    _myInstVar += newValue;         // subclass state updated before Notify
}
```

**Rule:** Always document which Subject operations trigger notifications. This is part of the public contract.

---

### 6. Avoiding Observer-Specific Update Protocols — Push and Pull Models

The subject can pass more or less information to observers during notification. The two extremes are:

**Push model:** Subject sends detailed change information as arguments to `Update`.

```cpp
// Subject pushes what it assumes observers need
void Subject::Notify(int changedValue, int oldValue) {
    for each o: o->Update(this, changedValue, oldValue);
}
```

- Advantage: Observer does not need to query the subject — efficient when all observers need the same data.
- Disadvantage: The subject must assume it knows what observers need. If different observers need different data, the push parameters become a lowest-common-denominator compromise. Subjects become less reusable because they're coupled to observer data needs.

**Pull model:** Subject sends only its identity. Observers query what they need.

```cpp
// Subject sends only itself
void Subject::Notify() {
    for each o: o->Update(this);
}

// Observer pulls what it needs
void ConcreteObserver::Update(Subject* s) {
    _cachedValue = ((ConcreteSubject*)s)->GetRelevantState();
    Render();
}
```

- Advantage: Subject remains ignorant of observer needs. Maximum reusability.
- Disadvantage: Observer must know the concrete Subject type to call specific accessors (introduces a cast). Less efficient if determining what changed requires re-reading large state.

**Recommendation:** Pull is the default. It enforces the subject's ignorance of its observers. Add push parameters only when a specific piece of changed data is needed by all observers and the cost of polling for it would be significant.

---

### 7. Specifying Modifications of Interest Explicitly (Aspect-Based Registration)

In the basic pattern, every observer is notified of every change. This is wasteful when a subject produces multiple types of events and a given observer cares about only one.

**Aspect-based registration** lets observers declare which events they care about at subscription time:

```cpp
// Extended Attach — observer registers for a specific aspect
void Subject::Attach(Observer* o, Aspect& interest);

// Extended Update — aspect passed at notification time
void Observer::Update(Subject* s, Aspect& interest);
```

At notification time, the subject supplies the changed aspect and notifies only the observers registered for that aspect:

```cpp
void Subject::Notify(Aspect& changedAspect) {
    for each (observer, registeredAspect) in _observerMap:
        if registeredAspect == changedAspect:
            observer->Update(this, changedAspect);
}
```

This is particularly useful for document-based systems where a single document may produce text changes, layout changes, selection changes, and save-state changes — and different views care about different subsets.

---

### 8 and 9. Encapsulating Complex Update Semantics — the ChangeManager

When the dependency relationships between subjects and observers are complex, the standard direct-Notify approach breaks down in two ways:

1. **Redundant notifications:** An operation changes subjects A and B. Observer O observes both. When A notifies, O runs. When B notifies, O runs again. O has been updated twice for one logical change.

2. **Ordering problems:** If notification order matters (observer C must run before observer D because D reads data that C computes), the simple notification loop cannot express this.

**ChangeManager** addresses both. It is a compound of three patterns:
- **Observer:** subjects and observers still use the standard protocol
- **Mediator:** ChangeManager centralizes the subject-observer communication logic
- **Singleton:** exactly one ChangeManager exists per subsystem; all subjects and observers route through the same instance

**ChangeManager's three responsibilities:**
1. Maintains the subject-to-observer mapping — eliminates per-subject observer storage
2. Defines the update strategy — when and how observers are notified
3. Updates all dependent observers at the request of any subject

**Class structure:**

```
Subject ←────────────── ChangeManager ───────────────→ Observer
Attach(Observer o)       Register(Subject, Observer)     Update(Subject)
Detach(Observer)         Unregister(Subject, Observer)
Notify() ─────────→      Notify()
chman->Notify()               │
                          ┌───┴────────┐
                SimpleChangeManager  DAGChangeManager
```

**SimpleChangeManager:**

```
Notify():
  for each subject s in subjects:
    for each observer o of s:
      o->Update(s)
```

Naive — always notifies all observers. Correct when observers observe exactly one subject.

**DAGChangeManager:**

```
Notify():
  Pass 1 — mark:
    for each subject s in subjects:
      for each observer o of s:
        mark o as pending

  Pass 2 — update once each:
    for each marked observer o:
      o->Update(relevantSubject)
      unmark o
```

Handles directed acyclic graph dependencies. When an observer observes multiple subjects, it receives exactly one `Update` call regardless of how many subjects changed. `DAGChangeManager` is preferable to `SimpleChangeManager` when any observer observes more than one subject.

**Using ChangeManager:**

```cpp
// Subject delegates to ChangeManager instead of maintaining its own list
void Subject::Attach(Observer* o) {
    ChangeManager::Instance()->Register(this, o);
}

void Subject::Notify() {
    ChangeManager::Instance()->Notify();
}
```

The Singleton `ChangeManager::Instance()` can be initialized with either strategy at startup, making it possible to change the update strategy without touching Subject or Observer classes.

---

### 10. Combining the Subject and Observer Roles

Languages without multiple inheritance (originally Smalltalk) sometimes define Subject and Observer together in a single root class, making all objects potential subjects and observers without any additional inheritance.

In languages with multiple inheritance (C++), a class can inherit from both `Subject` and `Observer` simultaneously, producing an object that can both publish changes and react to changes from other subjects:

```cpp
class DigitalClock : public Widget, public Observer {
    // Widget provides UI rendering capability
    // Observer provides Update() — reacts to ClockTimer changes
    // DigitalClock itself is not a Subject, but could be if it had dependents
};
```

This also applies to systems where an observer itself is a subject for downstream observers — common in reactive pipelines. In that case, the observer's `Update` method mutates its own state and then calls its own `Notify`, propagating the change downstream.

**Warning:** When an object is both subject and observer and part of a cycle, cascade updates are possible. Use `DAGChangeManager` to prevent redundant updates, or add a change-guard to prevent re-notification while an update is in progress:

```cpp
void ComboSubjectObserver::Update(Subject* s) {
    if (_updating) return;   // prevent re-entrant notification
    _updating = true;
    // update own state based on s
    Notify();                // propagate to own observers
    _updating = false;
}
```

---

## Participants Summary

| Participant | Role | Knows about |
|-------------|------|-------------|
| `Subject` | Maintains observer list; provides Attach/Detach/Notify | Abstract `Observer` only |
| `Observer` | Defines Update interface | Nothing about Subject state |
| `ConcreteSubject` | Stores subject state; calls Notify on change | Its own state and the abstract Observer |
| `ConcreteObserver` | Implements Update; holds reference to ConcreteSubject | ConcreteSubject (for GetState queries) |
| `ChangeManager` | Mediates subject-observer mapping; controls update strategy | Both Subject and Observer interfaces |

---

## Collaborations Sequence

```
aConcreteSubject     aConcreteObserver     anotherConcreteObserver
      │                     │                         │
      │← SetState() ────────│                         │
      │                     │                         │
      │── Notify() ─────────→                         │
      │                     │                         │
      │    ← Update() ──────│                         │
      │    ── GetState() ───→                         │
      │                     │                         │
      │── Update() ─────────────────────────────────→ │
      │                              ← GetState() ────│
      │                                               │
```

Note: the observer that initiates the change (`SetState`) postpones its own update until it receives notification from the subject. `Notify` is not always called by the subject — it can be called by an observer or by an external client (see Implementation Concern 3).

---

## Consequences

### 1. Abstract Coupling Between Subject and Observer

The subject knows only that it has a list of observers conforming to the abstract `Observer` interface. It does not know the concrete class of any observer. The coupling is minimal and abstract. This allows Subject and Observer to belong to different layers of abstraction in a system — a lower-level subject can communicate with a higher-level observer without violating layering. If tightly coupled, the combined object would be forced to exist in one layer, potentially violating the layering abstraction.

### 2. Support for Broadcast Communication

Unlike an ordinary request with one sender and one receiver, a subject's notification is broadcast to all subscribed observers. The subject does not care how many observers exist. Observers can be added and removed at any time without modifying the subject. It is up to each observer whether to handle or ignore a notification.

### 3. Unexpected Updates

Because observers have no knowledge of each other's presence, they cannot predict the ultimate cost of a change to the subject. A seemingly innocuous state change may cause a cascade of updates through multiple observers and their dependent objects. Furthermore, the simple Update protocol provides no information about *what* changed — only that *something* changed. Observers must work to discover what changed (pull model overhead), or the subject must provide that information (push model coupling). Ill-defined dependency criteria lead to spurious updates that are difficult to track down.

---

## Related Patterns

| Pattern | Relationship |
|---------|-------------|
| **Mediator** | ChangeManager acts as a Mediator between subjects and observers. It encapsulates the update communication so neither subject nor observer needs to know the other's full protocol. |
| **Singleton** | ChangeManager is typically a Singleton — there is one per subsystem, and it must be globally accessible to both subjects and observers. |

---

## Known Uses

- **Smalltalk Model/View/Controller (MVC):** The first and best-known application. Model is Subject; View is Observer. Controller mediates input to model changes. View re-renders on model notification.
- **InterViews:** Defines explicit `Observer` and `Observable` (for Subject) classes.
- **Andrew Toolkit:** Calls subjects "data objects" and observers "views."
- **Unidraw:** Splits graphical editor objects into View (observer) and Subject parts.
- **Qt (signals/slots):** A type-safe, language-integrated implementation of Observer with aspect-based registration (signals map to aspects).
- **Java EventListener model:** Observer implemented as interface; aspect-based (event type per listener interface).
- **RxJS / Reactive Extensions:** Observer generalized to streams — an observable (subject) emits values; subscribers (observers) react to each emission.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)