State Pattern Interview Deep Dive
Common Interview Questions
Q1: Who should own state transition logic - Context or State classes?
Answer: Typically, State classes own transitions because they understand the business rules for when transitions should occur. This keeps transition logic encapsulated with state-specific behavior. However, if transitions follow a strict, predetermined sequence (like a workflow: Draft → Review → Approved), the Context can manage a state machine table instead. Choose based on complexity: if transition rules are complex and state-dependent, let States decide. But if transitions follow a simple linear or table-driven flow, Context can manage the state machine.
Q2: How do you handle shared data between states?
Answer: The Context holds all shared data (inventory, balance, user info). States receive the Context as a parameter and call getter/setter methods to access data. Never pass raw data to state constructors, as this creates tight coupling. States should be stateless except for the Context reference. For example, in a vending machine, DispensingState.dispense(context) calls context.getInventory() and context.getBalance() rather than storing these values in the state itself.
Q3: Should state objects be singletons or created fresh each transition?
Answer: If states are stateless (they only contain behavior, no instance variables), use singletons or static instances to avoid object creation overhead. But if states need to store transition-specific data (like "which product was selected"), create new instances per transition. In interviews, start with stateless singleton pattern for simplicity, then explain: "If we need to track transaction-specific data, we would instantiate new state objects instead."
Machine Coding Considerations
Step-by-Step Implementation Approach:
First, identify all possible states by listing nouns in requirements (Idle, Processing, Complete).
Second, identify all operations/actions that behavior varies by state (insert, cancel, dispense).
Third, create State interface with all operations. Each state implements all methods, even if just to reject the operation.
Fourth, design Context with state reference and data fields. Implement delegation methods that call current state.
Fifth, implement each Concrete State, focusing on happy path first, then add validation and error cases.
Sixth, add state transition logic in states, ensuring every possible transition is handled or explicitly rejected.
Advanced Variations
1. Hierarchical State Pattern
States can have substates. Example: A LoggedInState might have substates like BrowsingState and CheckoutState. The parent state handles common behavior (like logout), while substates handle specific behavior. This is useful when states share common functionality but also have unique aspects.
2. State History/Memento Integration
Combine State Pattern with Memento Pattern to support undo/redo. Store previous states in a stack so users can revert to prior states. The Context maintains a state history rather than just current state. This is common in document editors or drawing applications.
3. Concurrent States
An object can be in multiple orthogonal states simultaneously. Example: A phone can be in LockedState AND ChargingState at the same time since these are independent concerns. Implement by having the Context maintain multiple state references for different aspects.
Common Pitfalls in Interviews
Avoid These Mistakes:
- Forgetting null checks: Always validate current state is not null before delegation
- Circular state references: Be careful when states reference each other; prefer factory methods in Context
- Forgetting to handle all operations: Every state must implement every operation, even if just throwing an exception
- Exposing state classes to client: Client should only interact with Context, never directly instantiate states
- Putting business logic in Context: Context should be a thin delegator; logic belongs in states
Real Interview Problem: Parking Lot Spot States
Problem: Design parking spot states: Available, Occupied, Reserved, UnderMaintenance
Key decisions to discuss:
- Can you reserve an occupied spot? (No - AvailableState allows reserve, OccupiedState rejects it)
- Can you park in a reserved spot? (Only if you are the reserver - ReservedState checks vehicle ID)
- How does maintenance affect reservation? (UnderMaintenanceState clears reservations and rejects all parking)
- Who triggers state changes? (States trigger: after parking, OccupiedState. After leaving, AvailableState. Maintenance is external)
Code Smell to Refactor
handleCancel() {
if (status == PENDING) {
// cancel logic
} else if (status == SHIPPED) {
// return logic
} else if ...
}
}
handleCancel() {
currentState.cancel(this)
}
}
class PendingState {
cancel(order) {...}
}