It allows an object to change its behavior when its internal state changes.
if/else or switch.// State
interface State {
insertCoin(turnstile: Turnstile): void;
push(turnstile: Turnstile): void;
}
class LockedState implements State {
insertCoin(turnstile: Turnstile): void {
console.log("Coin inserted. Turnstile unlocked.");
turnstile.setState(turnstile.unlockedState);
}
push(turnstile: Turnstile): void {
console.log("Turnstile is locked. Can't push.");
}
}
class UnlockedState implements State {
insertCoin(turnstile: Turnstile): void {
console.log("Already unlocked. Return coin.");
}
push(turnstile: Turnstile): void {
console.log("Turnstile pushed. Locking turnstile.");
turnstile.setState(turnstile.lockedState);
}
}
// Context
class Turnstile {
lockedState: State;
unlockedState: State;
private currentState: State;
constructor() {
this.lockedState = new LockedState();
this.unlockedState = new UnlockedState();
this.currentState = this.lockedState;
}
setState(state: State): void {
this.currentState = state;
}
insertCoin(): void {
this.currentState.insertCoin(this);
}
push(): void {
this.currentState.push(this);
}
}
// Client Code
const turnstile = new Turnstile();
turnstile.push(); // Turnstile is locked. Can't push.
turnstile.insertCoin(); // Coin inserted. Turnstile unlocked.
turnstile.push(); // Turnstile pushed. Locking turnstile.
// State
type State interface {
InsertCoin(t *Turnstile)
Push(t *Turnstile)
}
type LockedState struct{}
func (l *LockedState) InsertCoin(t *Turnstile) {
fmt.Println("Coin inserted. Turnstile unlocked.")
t.SetState(t.unlockedState)
}
func (l *LockedState) Push(t *Turnstile) {
fmt.Println("Turnstile is locked. Can't push.")
}
type UnlockedState struct{}
func (u *UnlockedState) InsertCoin(t *Turnstile) {
fmt.Println("Already unlocked. Return coin.")
}
func (u *UnlockedState) Push(t *Turnstile) {
fmt.Println("Turnstile pushed. Locking turnstile.")
t.SetState(t.lockedState)
}
// Context
type Turnstile struct {
lockedState State
unlockedState State
currentState State
}
func NewTurnstile() *Turnstile {
t := &Turnstile{}
t.lockedState = &LockedState{}
t.unlockedState = &UnlockedState{}
t.currentState = t.lockedState
return t
}
func (t *Turnstile) SetState(state State) {
t.currentState = state
}
func (t *Turnstile) InsertCoin() {
t.currentState.InsertCoin(t)
}
func (t *Turnstile) Push() {
t.currentState.Push(t)
}
// Client Code
turnstile := NewTurnstile()
turnstile.Push() // Turnstile is locked. Can't push.
turnstile.InsertCoin() // Coin inserted. Turnstile unlocked.
turnstile.Push() // Turnstile pushed. Locking turnstile.
If we find that you're introducing entirely unrelated behaviors—like turning lights on and off—it usually means you're dealing with a different concern or domain within your system.