Behavioral
Step 7 in the OO & Low-Level Design path · 10 concepts · 0 problems
📘 Learn Behavioral from zero
From zero: creational patterns answer "how are objects instantiated"; structural patterns answer "how are objects composed and connected"; behavioral patterns answer "how do objects communicate and divide responsibility at runtime." Behavioral patterns are all about turning a verb, an algorithm, a request, a notification, a state-change, into an object you can swap, queue, or reroute.
Vivid analogy, the Strategy pattern as a navigation app. You want to go from home to office. The app does not bake one route-finder into its code. Instead it offers buttons: Drive, Walk, Cycle, Transit. Each is a self-contained algorithm behind the same interface, computeRoute(start, end). The app (the context) just holds whichever one you picked and calls that method. It never writes if (mode == DRIVE) ... else if (mode == WALK) .... Adding "Scooter" later means writing one new strategy class; the app code is untouched.
Concrete worked example. A checkout needs a shipping cost.
- Define an interface
ShippingStrategy { int cost(Order o); }. - Implement
FlatRate(returns 500),ByWeight(returnso.weight * 10),Free(returns 0). - The
Cartcontext stores aShippingStrategy strategyand exposessetStrategy(...). - At runtime:
cart.setStrategy(new ByWeight()); cart.checkout();delegates tostrategy.cost(order).
You have replaced a growing if/else with polymorphism, the open/closed principle in action: open to new behavior, closed to modification.
The single key insight: behavioral patterns convert a behavior, an algorithm, request, transition, or notification, into a first-class object so it can be selected, sequenced, or rerouted independently of the code that uses it. Favor composition over conditionals.
✨ Added by the guide to build intuition — not from the source course.
🎯 Guided practice
- Easy, Observer (a YouTube channel). A channel must notify all subscribers when it uploads. Step 1, find the one-to-many trigger: "when X changes, notify an unknown number of dependents", that is Observer. Step 2, define the contract:
interface Subscriber { void update(String video); }. Step 3, the subject holds a list:ChannelkeepsList<Subscriber> subswithsubscribe()andunsubscribe(). Step 4, push on change:upload(v)loopsfor (s : subs) s.update(v), O(number of subscribers). Step 5, decouple:Channelknows nothing about concrete subscriber types, only the interface, so anEmailSuborSMSSubcan be added with zero changes toChannel. Watch out: a subscriber that is discarded but never unsubscribes keeps getting notified and cannot be garbage-collected (lapsed listener), so always pair subscribe with unsubscribe, or hold observers via weak references. - Medium, State (a vending machine). Model states:
NoCoin,HasCoin,Dispensing. Step 1, spot the smell: behavior (insertCoin,pressButton) depends on the current mode and you would otherwise write nestedif (state == ...), that signals State. Step 2, make each state a class implementinginterface State { void insertCoin(); void pressButton(); }. Step 3, the context delegates:VendingMachineholdsState currentand forwards every call, e.g.current.pressButton(). Step 4, states drive transitions: inNoCoin.insertCoin()callmachine.setState(new HasCoin()); inHasCoin.pressButton()transition toDispensing, then back toNoCoinonce dispensed. Step 5, contrast with Strategy: here the state objects switch the context to one another based on transitions, whereas a Strategy is chosen once by the client and never reassigns itself, this is the canonical distinction interviewers probe. Result: adding aSoldOutstate means one new class plus its transition edges, with no edits to a giant conditional that no longer exists.
✨ Added by the guide — work these before the full problem set.