Exercise 3: Why Observer's Ignorance and State's Ignorance Are the Same Idea — Possible Solution ==================================================================== WHAT STOCK DOESN'T NEED TO KNOW ------------------------------ This chapter verified Stock._notify() calls observer.update(symbol, price) identically on PriceLogger, AlertService, and (in Exercise 1) MovingAverageTracker - three observers with completely different internal logic (recording every price, conditionally flagging one, computing a running average). Stock's own code never branches on which kind of observer it's talking to; it just trusts that whatever is in self._observers has an update() method that does something useful with the notification. WHAT ORDERCONTEXT DOESN'T NEED TO KNOW ------------------------------ This chapter verified OrderContext.ship() is exactly one line - self.state.ship(self) - regardless of whether self.state is a PendingState (where ship() raises an exception) or a PaidState (where ship() transitions to ShippedState). OrderContext's own code never branches on which state it currently holds; it just trusts that whatever is in self.state has a ship() method that does the right thing for that specific state. THE SHARED UNDERLYING IDEA ------------------------------ Both cases hand off a decision to an object the caller doesn't inspect. Stock hands "what should happen now that the price changed" to each observer object; OrderContext hands "what should happen when ship() is called" to whichever state object currently sits in self.state. In both patterns, the calling code (Stock._notify(), OrderContext.ship()) stays exactly the same size and shape no matter how many observer types or state types exist - all the actual type-specific behavior lives inside the objects being delegated to, not inside the code doing the delegating. WHY THE PATTERNS STILL COUNT AS DIFFERENT PATTERNS ------------------------------ The shared idea is delegation without type-checking - but WHO initiates a change differs. In Observer, an outside event (a price change) causes ONE object (Stock) to notify MANY objects (every attached observer) about something that already happened. In State, a single object (OrderContext) delegates to exactly ONE current object (self.state) to decide what CAN happen next - and that one state object, not an outside caller, is the one deciding when to replace itself (order.state = PaidState()). Observer is one-to-many notification after the fact; State is one-to-one delegation that decides the future. WHY THIS WORKS AS AN ANSWER ------------------------------ The answer grounds the comparison in this chapter's own verified code (Stock._notify()'s loop and OrderContext.ship()'s one-line delegation), names the shared mechanism precisely (delegation to an object whose concrete type the caller never inspects), and then draws a genuine distinction between the two patterns rather than collapsing them into being the same thing.