State
Overview
Allow an object to alter its behavior when its internal state changes.
When to use
- Behavior varies based on state.
- You want to avoid large conditionals.
- State transitions belong inside the object rather than in client code.
Java example
interface State {
String label();
void publish(Document document);
}
class DraftState implements State {
public String label() {
return "draft";
}
public void publish(Document document) {
document.setState(new PublishedState());
}
}
class PublishedState implements State {
public String label() {
return "published";
}
public void publish(Document document) {
// already published
}
}
class Document {
private State state = new DraftState();
void publish() {
state.publish(this);
}
void setState(State state) {
this.state = state;
}
String render() {
return state.label();
}
}
TypeScript example
interface State {
label(): string;
publish(document: Document): void;
}
class DraftState implements State {
label(): string {
return 'draft';
}
publish(document: Document): void {
document.setState(new PublishedState());
}
}
class PublishedState implements State {
label(): string {
return 'published';
}
publish(_document: Document): void {}
}
class Document {
private state: State = new DraftState();
publish(): void {
this.state.publish(this);
}
setState(state: State): void {
this.state = state;
}
render(): string {
return this.state.label();
}
}
Pros and cons
Pros:
- Removes complex conditional logic.
- State transitions are explicit.
Cons:
- More classes for each state.
- Can be overkill for simple cases.
Common pitfalls
- States that leak knowledge of too many other states.
- Hiding transitions across unrelated services.