The State pattern lets an object behave differently depending on its current state, without cluttering the object itself with conditionals. Each state gets its own class, and the object just delegates to whichever one is active.
// State interface
class State {
handle(context) {
throw new Error("This method must be overridden!");
}
}
// Concrete States
class ConcreteStateA extends State {
handle(context) {
console.log("State A handling request.");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State {
handle(context) {
console.log("State B handling request.");
context.setState(new ConcreteStateA());
}
}
// Context
class Context {
constructor(state) {
this.setState(state);
}
setState(state) {
console.log(`State changed to ${state.constructor.name}`);
this.state = state;
}
request() {
this.state.handle(this);
}
}-
State Interface
- The
Stateclass defines an interface for encapsulating the behavior associated with a particular state of theContext.
- The
-
Concrete States
ConcreteStateAandConcreteStateBare concrete implementations of theStateinterface.- Each concrete state implements the
handlemethod, which performs an action and transitions the context to the next state.
-
Context
- The
Contextclass maintains an instance of aStatesubclass that defines the current state. - The
setStatemethod changes the current state and logs the state transition. - The
requestmethod delegates the request to the current state'shandlemethod.
- The
const context = new Context(new ConcreteStateA());
context.request(); // State A handling request. State changed to ConcreteStateB
context.request(); // State B handling request. State changed to ConcreteStateA- A
Contextobject is created with an initial state (ConcreteStateA). - Calling
request()on the context triggers the current state'shandlemethod, which performs an action and transitions to the next state.
State transitions happen inside the state classes themselves: ConcreteStateA.handle() decides to transition to B, and vice versa. The Context never contains transition logic; it just calls request() and lets the active state figure out what happens next. This is what keeps Context clean when the number of states grows.