Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

State Diagrams
LLD

State Diagrams

Understand how state diagrams represent object states, transitions, events, and lifecycle behavior.

The Problem It Solves

An order that can be cancelled after shipping is a production incident; so is an order stuck forever in “processing.” Both bugs come from implicit lifecycles — states and their legal transitions living only in scattered if (status == ...) checks. A state diagram makes the lifecycle explicit and complete: every legal path visible, every illegal transition declared impossible.

Anatomy

            ┌─────────┐  pay() [payment ok]   ┌─────────┐
 ●─────────►│ PLACED  ├──────────────────────►│  PAID   │
 (initial)  └────┬────┘                       └────┬────┘
                 │ cancel()                        │ ship()
                 ▼                                 ▼
           ┌──────────┐                      ┌──────────┐
           │CANCELLED │                ┌─────│ SHIPPED  │
           └──────────┘                │     └────┬─────┘
                                       ▼ deliver()▼
                                     ┌──────────────┐
                          ●──────────│  DELIVERED   │───►◉ final
                    refund window    └──────────────┘

 notation: rounded box = state · arrow = transition labeled
           event [guard] / action · ● initial · ◉ terminal

Each arrow carries the event that triggers it, optionally a guard ([payment ok] — transition only if true) and an action (/ send email). Anything without an arrow — “cancel a SHIPPED order” — is defined as impossible, which is precisely the value.

Mapping to Code

UML elementJava form
Statesenum OrderStatus
Transition tableMap<State, Map<Event, State>> or switch in one method
Guardspredicate evaluated before applying
Illegal eventexception or explicit rejection — never silent ignore
enum Status { PLACED, PAID, SHIPPED, DELIVERED, CANCELLED }

class Order {
    private Status status = Status.PLACED;

    void pay(PaymentResult r) {
        requireStatus(Status.PLACED);              // guard by construction
        if (!r.ok()) return;                        // guard condition
        this.status = Status.PAID;                  // single mutation point
    }
    void cancel() {
        if (status != Status.PLACED) throw new IllegalStateException(...);
        status = Status.CANCELLED;
    }
}

One mutation method per event, each validating current state first — invariants (“no cancel after ship”) become structural rather than disciplinary.

When to Graduate to the State Pattern

Two triggers: transitions carry state-specific behavior (each state defines different responses to the same events), or the switch table grows unwieldy. Then each state becomes a class delegating behavior — see behavioral/state page. For pure status tracking, the enum-plus-guards version above is simpler and correct.

Interview Application

  • Drawing the order/booking/payment lifecycle before coding signals completeness thinking.
  • The TTL question — “who fires the transition when a hold expires?” — expects either a scheduled job modeled as a time-based event (after(15m) / expire) on the diagram.

Common Mistakes

  • Terminal state missing → objects that can never be GC’d/archived.
  • Guardless fan-in: allowing any state to reach CANCELLED — usually wrong; cancellation windows exist for reasons.
  • Modeling screen flow instead of object lifecycle — states belong to domain entities.

My Private Notes

Notes are auto-saved locally to this device.