Behavioral triggers: Strategy, Observer, Template Method,… — Cracked Java
// Low-Level Design (LLD / OOD) · Design Pattern Quick Reference (Applied)
MidSystem Design

Behavioral triggers: Strategy, Observer, Template Method, Command, State, Chain of Responsibility.

Behavioral patterns answer "how do objects interact and divide responsibility?" These are the workhorses of LLD rounds — Strategy, Observer, and State appear in a majority of the classic problems. (Full theory: OOP module's behavioral patterns topic.)

Quick map

PatternLLD trigger phraseReach for it when
Strategy"the algorithm varies (pricing, matching, eviction)"Interchangeable algorithms, chosen at runtime
Observer"notify many parties when something changes"One-to-many event broadcast
State"behavior depends on which state it's in"An object with a lifecycle / state machine
Template Method"same skeleton, steps differ per subtype"Fixed algorithm, pluggable steps
Command"encapsulate a request for queue/undo/log"Actions as first-class objects
Chain of Responsibility"pass a request along until someone handles it"Ordered handlers, fallback, pipelines

Strategy — swappable algorithm

The most common LLD pattern. Trigger: "pricing can be hourly or flat," "eviction is LRU or LFU," "matching is nearest or surge."

interface PricingStrategy { double price(Ticket t, Instant exit); }
class HourlyPricing  implements PricingStrategy { /* ... */ }
class WeekendPricing implements PricingStrategy { /* ... */ }

class ParkingLot {
    private PricingStrategy pricing;          // injected, swappable
    void setPricing(PricingStrategy p) { this.pricing = p; }
}

Observer — broadcast on change

Trigger: "displays / waiting users should be notified when a spot frees up."

interface SpotObserver { void onAvailable(SpotType type); }
class Floor {
    private final List<SpotObserver> observers = new CopyOnWriteArrayList<>();
    void release(Spot s) {
        s.free();
        observers.forEach(o -> o.onAvailable(s.type()));   // notify all
    }
}

State — behavior per lifecycle stage

Trigger: "a vending machine is Idle / HasMoney / Dispensing" or "an order is Placed / Paid / Shipped." Replaces a giant switch(state).

interface VendingState { VendingState insertCoin(); VendingState dispense(); }
class IdleState     implements VendingState { /* coin -> HasMoneyState */ }
class HasMoneyState implements VendingState { /* dispense -> IdleState */ }

class VendingMachine {
    private VendingState state = new IdleState();
    void insertCoin() { state = state.insertCoin(); }   // transition
}

Template Method — fixed skeleton, varied steps

Trigger: "every report does load → process → format, but each type formats differently."

abstract class ReportGenerator {
    final void generate() { load(); process(); format(); }  // fixed order
    abstract void format();                                  // subclass varies this
    void load() { /* shared */ }  void process() { /* shared */ }
}

Command — request as an object

Trigger: "undo/redo," "queue the action," "log and replay." Each action becomes an object with execute()/undo().

interface Command { void execute(); void undo(); }
class MoveCommand implements Command {
    public void execute() { piece.moveTo(target); }
    public void undo()    { piece.moveTo(origin); }
}   // a Stack<Command> gives you undo

Chain of Responsibility — pass until handled

Trigger: "try email, then SMS, then push," "dispense $100s then $50s then $20s," "auth → rate-limit → log."

abstract class Handler {
    protected Handler next;
    Handler setNext(Handler n) { this.next = n; return n; }
    void handle(Request r) {
        if (canHandle(r)) process(r);
        else if (next != null) next.handle(r);   // pass along
    }
}

Mark your status