State Design Pattern
Structural: State Pattern
What is the State Design Pattern in JavaScript?
View Answer:

This pattern's objects are as follows:
Context -- example code: TrafficLight
- exposes an interface that supports clients of the service
- keeps a reference to a state object that defines the current state.
- Allows State objects to change their current state to another state.
State -- example code: Red, Yellow, Green
- captures the state's values and associated behavior
Here's an example of a Traffic Light system using the State Design Pattern.
class TrafficLight {
constructor() {
this.states = [new GreenLight(), new YellowLight(), new RedLight()];
this.current = this.states[0];
}
change() {
const totalStates = this.states.length;
let currentIndex = this.states.findIndex(light => light === this.current);
if (currentIndex + 1 < totalStates) this.current = this.states[currentIndex + 1];
else this.current = this.states[0];
}
sign() {
return this.current.sign();
}
}
class Light {
constructor(light) {
this.light = light;
}
}
class GreenLight extends Light {
constructor() {
super('green');
}
sign() {
return 'Go';
}
}
class YellowLight extends Light {
constructor() {
super('yellow');
}
sign() {
return 'Caution';
}
}
class RedLight extends Light {
constructor() {
super('red');
}
sign() {
return 'Stop';
}
}
// usage
const trafficLight = new TrafficLight();
console.log(trafficLight.sign()); // Green: Go
trafficLight.change();
console.log(trafficLight.sign()); // Yellow: Caution
trafficLight.change();
console.log(trafficLight.sign()); // Red: Stop
trafficLight.change();
// Example output:
// Go
// Caution
// Stop
In this example, the TrafficLight class represents the Context, and it maintains a reference to a state object (current) which serves as the Current State. GreenLight, YellowLight, and RedLight classes represent Concrete States, each with different behaviors encapsulated in the sign() method.
The State pattern belongs to which pattern category?
View Answer:
When should you utilize the State Design Pattern in JavaScript?
View Answer:
What are some of the advantages of employing the State pattern?
View Answer:
- Singular Responsibility Principle -- Separate the code related to each state into separate classes.
- The Open/Closed Principle - Add new states without modifying existing state classes or the context.
- Simplify the contextual code by removing bulky state machine conditionals.
What are some drawbacks of using the State Design Pattern?
View Answer:
Are there any alternatives to using the State pattern?
View Answer:
Why use the State Design Pattern in JavaScript?
View Answer:
What kind of problems does the State Design Pattern solve?
View Answer:
How does the State Design Pattern differ from the Strategy Pattern?
View Answer:
Can you explain the concept of 'Context' and 'State' in the State Design Pattern?
View Answer:
Here's an example with a Water object that changes state between Solid, Liquid, and Gas.
class Water {
constructor() {
this.state = new SolidState(this);
}
heat() {
this.state.heat();
}
cool() {
this.state.cool();
}
changeState(state) {
this.state = state;
}
printState() {
this.state.printState();
}
}
class State {
constructor(water) {
this.water = water;
}
heat() {
throw new Error('This method must be overwritten!');
}
cool() {
throw new Error('This method must be overwritten!');
}
printState() {
throw new Error('This method must be overwritten!');
}
}
class SolidState extends State {
heat() {
console.log('Heating ice. Turning to water.');
this.water.changeState(new LiquidState(this.water));
}
cool() {
console.log('Ice is already cool.');
}
printState() {
console.log('The water is solid.');
}
}
class LiquidState extends State {
heat() {
console.log('Heating water. Turning to gas.');
this.water.changeState(new GasState(this.water));
}
cool() {
console.log('Cooling water. Turning to ice.');
this.water.changeState(new SolidState(this.water));
}
printState() {
console.log('The water is liquid.');
}
}
class GasState extends State {
heat() {
console.log('Gas is already hot.');
}
cool() {
console.log('Cooling gas. Turning to water.');
this.water.changeState(new LiquidState(this.water));
}
printState() {
console.log('The water is gas.');
}
}
const water = new Water();
water.printState(); // The water is solid.
water.heat(); // Heating ice. Turning to water.
water.printState(); // The water is liquid.
water.heat(); // Heating water. Turning to gas.
water.printState(); // The water is gas.
water.cool(); // Cooling gas. Turning to water.
water.printState(); // The water is liquid.
In this example, Water is the "Context". The "State" is an interface represented by the State class, and SolidState, LiquidState, and GasState are the "Concrete States". The heat() and cool() methods in the Water class delegate to the current state's corresponding methods.