π§© State Pattern
β Intentβ
- Change an object's behavior based on its current state
- Delegate state-specific responsibilities to separate classes
β Motivationβ
- Effective when user types can be treated as internal states
- Even the logic for changing state itself can be handled by the state objects
β When to Useβ
- When the current state becomes the central concern, such as user rank or login status
- When you need controlled state transitions
β Code Exampleβ
- TypeScript
- PHP
- Python
// ηΆζ
γ€γ³γΏγΌγγ§γΌγΉ
interface DiscountState {
calculate(basePrice: number): number;
}
// εηΆζ
γ―γ©γΉ
class StudentState implements DiscountState {
calculate(basePrice: number): number {
return basePrice * 0.8;
}
}
class MemberState implements DiscountState {
calculate(basePrice: number): number {
return basePrice * 0.9;
}
}
class VIPState implements DiscountState {
calculate(basePrice: number): number {
return basePrice * 0.7;
}
}
class DefaultState implements DiscountState {
calculate(basePrice: number): number {
return basePrice;
}
}
// γ³γ³γγγΉγ
class DiscountContext {
private state: DiscountState;
constructor(state: DiscountState) {
this.state = state;
}
setState(state: DiscountState) {
this.state = state;
}
calculate(basePrice: number): number {
return this.state.calculate(basePrice);
}
}
// ε©η¨δΎ
const context = new DiscountContext(new StudentState());
console.log(context.calculate(1000)); // 800
<?php
interface DiscountState {
public function calculate(float $basePrice): float;
}
class StudentState implements DiscountState {
public function calculate(float $basePrice): float {
return $basePrice * 0.8;
}
}
class MemberState implements DiscountState {
public function calculate(float $basePrice): float {
return $basePrice * 0.9;
}
}
class VIPState implements DiscountState {
public function calculate(float $basePrice): float {
return $basePrice * 0.7;
}
}
class DefaultState implements DiscountState {
public function calculate(float $basePrice): float {
return $basePrice;
}
}
class DiscountContext {
private DiscountState $state;
public function __construct(DiscountState $state) {
$this->state = $state;
}
public function setState(DiscountState $state): void {
$this->state = $state;
}
public function calculate(float $basePrice): float {
return $this->state->calculate($basePrice);
}
}
// ε©η¨δΎ
$context = new DiscountContext(new StudentState());
echo $context->calculate(1000) . PHP_EOL; // 800
from abc import ABC, abstractmethod
class DiscountState(ABC):
@abstractmethod
def calculate(self, base_price: float) -> float:
pass
class StudentState(DiscountState):
def calculate(self, base_price: float) -> float:
return base_price * 0.8
class MemberState(DiscountState):
def calculate(self, base_price: float) -> float:
return base_price * 0.9
class VIPState(DiscountState):
def calculate(self, base_price: float) -> float:
return base_price * 0.7
class DefaultState(DiscountState):
def calculate(self, base_price: float) -> float:
return base_price
class DiscountContext:
def __init__(self, state: DiscountState):
self._state = state
def set_state(self, state: DiscountState):
self._state = state
def calculate(self, base_price: float) -> float:
return self._state.calculate(base_price)
# ε©η¨δΎ
context = DiscountContext(StudentState())
print(context.calculate(1000)) # 800
β Explanationβ
This code applies the State
pattern to isolate discount logic into separate states that can be switched dynamically.
The State
pattern allows an object to alter its behavior based on internal state, eliminating conditional branches and improving readability and maintainability.
1. Overview of the State Patternβ
-
State: Defines an interface for behavior specific to each state
- Represented here by
DiscountState
- Represented here by
-
ConcreteState: Implements the
State
interface to provide specific behavior for each state- Implemented by
StudentState
,MemberState
,VIPState
, andDefaultState
in this code
- Implemented by
-
Context: Holds the current state and delegates behavior based on it
- Represented by
DiscountContext
in this code
- Represented by
2. Key Classes and Their Rolesβ
-
DiscountState
- Common interface for discount calculation
- Defines the method
calculate(basePrice: number): number
-
StudentState
,MemberState
,VIPState
,DefaultState
- Concrete state classes implementing
DiscountState
- Each applies a different discount rate
- Concrete state classes implementing
-
DiscountContext
- Context class that maintains the current state
- Allows switching state via
setState
, and executes the discount calculation via the current state'scalculate
method
3. UML Class Diagramβ
4. Benefits of the State Patternβ
- Eliminates Conditional Branching: By moving logic into state classes, conditionals can be eliminated
- Extensibility: Adding a new state requires only implementing
DiscountState
- Dynamic Switching: Allows state transitions at runtime in a clean and controlled way
This design clearly separates behavior by state and provides a safe mechanism for managing transitionsβespecially effective in scenarios with growing conditional logic.