Python状态模式:告别订单状态的if-else地狱
前言
订单状态管理写过吗?待支付、已支付、已发货、已完成、已取消... 每个状态能做的操作不一样,状态之间的转换还有规则限制。
很多人的第一反应是 if-else:
python
if order.status == "pending":
if action == "pay":
order.status = "paid"
elif action == "cancel":
order.status = "cancelled"
elif order.status == "paid":
if action == "ship":
order.status = "shipped"
# ...几十个分支
状态一多,这代码就没法看了。状态模式就是专门解决这个问题的------把每个状态的行为封装成独立的类,状态切换变得清晰可控。
这篇文章从最简单的 Python 实现开始,然后用 transitions 库简化开发,最后手撸一个完整的 FastAPI 订单状态机。
🏠个人主页:山沐与山
文章目录
一、状态模式是什么
1.1 核心思想
状态模式让对象在内部状态改变时改变它的行为,看起来就像改变了它的类。
关键点:
- 状态决定行为:不同状态下,同一个方法有不同的实现
- 状态封装:每个状态是一个独立的类
- 状态转换:由状态类自己控制能转换到哪些状态
1.2 订单状态流转图
┌──────────┐
┌─────────│ 已取消 │
│ cancel └──────────┘
│ ▲
│ │ cancel (仅待支付可取消)
│ │
┌────┴────┐ ┌────┴────┐ ┌─────────┐ ┌─────────┐
│ 待支付 │───▶│ 已支付 │───▶│ 已发货 │───▶│ 已完成 │
└─────────┘pay └─────────┘ship└─────────┘ └─────────┘
confirm ▲
│ │
└──────────────┘
你看,每个箭头都是一次状态转换,每次转换都有触发条件。
1.3 不用状态模式的噩梦
代码来自 bad_order.py:
python
class Order:
def __init__(self):
self.status = "pending"
def pay(self):
if self.status == "pending":
self.status = "paid"
print("[支付] 支付成功")
elif self.status == "paid":
raise Exception("订单已支付,请勿重复支付")
elif self.status == "shipped":
raise Exception("订单已发货,无法支付")
elif self.status == "completed":
raise Exception("订单已完成")
elif self.status == "cancelled":
raise Exception("订单已取消,无法支付")
def ship(self):
if self.status == "pending":
raise Exception("订单未支付,无法发货")
elif self.status == "paid":
self.status = "shipped"
print("[发货] 已发货")
elif self.status == "shipped":
raise Exception("订单已发货")
elif self.status == "completed":
raise Exception("订单已完成")
elif self.status == "cancelled":
raise Exception("订单已取消")
def cancel(self):
if self.status == "pending":
self.status = "cancelled"
print("[取消] 订单已取消")
elif self.status == "paid":
# 已支付取消要退款
self.status = "cancelled"
self._refund()
print("[取消] 订单已取消,已退款")
elif self.status == "shipped":
raise Exception("订单已发货,无法取消")
# ... 还有更多
# 每加一个状态,所有方法都要改
# 每加一个操作,要写一堆 if-else
问题在哪?
- 代码膨胀:状态×操作 = 分支数量爆炸
- 难以维护:改一个状态的逻辑要翻遍整个类
- 容易出错 :漏掉某个分支就是
bug - 违反开闭原则:加新状态要改现有代码
二、Python基础实现
2.1 状态模式结构
先定义状态的抽象基类,代码来自 order_states.py:
python
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING
from datetime import datetime
if TYPE_CHECKING:
from order import Order
class OrderState(ABC):
"""订单状态抽象基类"""
name: str = "unknown"
@abstractmethod
def pay(self, order: "Order") -> None:
pass
@abstractmethod
def ship(self, order: "Order") -> None:
pass
@abstractmethod
def confirm(self, order: "Order") -> None:
pass
@abstractmethod
def cancel(self, order: "Order") -> None:
pass
def _invalid_operation(self, operation: str):
raise InvalidOperationError(
f"状态 [{self.name}] 不支持操作 [{operation}]"
)
class InvalidOperationError(Exception):
"""非法操作异常"""
pass
看到没?每个状态都要实现 pay、ship、confirm、cancel 这四个方法。
2.2 具体状态实现
2.2.1 待支付状态
python
class PendingState(OrderState):
"""待支付状态"""
name = "待支付"
def pay(self, order: "Order") -> None:
print("[支付] 处理支付...")
# 调用支付接口
order.paid_at = datetime.now()
order.set_state(PaidState())
print("[+] 支付成功")
def ship(self, order: "Order") -> None:
self._invalid_operation("发货")
def confirm(self, order: "Order") -> None:
self._invalid_operation("确认收货")
def cancel(self, order: "Order") -> None:
print("[取消] 取消订单...")
order.cancelled_at = datetime.now()
order.set_state(CancelledState())
print("[+] 订单已取消")
这个状态下只能支付或取消,其他操作都会抛出异常。
2.2.2 已支付状态
python
class PaidState(OrderState):
"""已支付状态"""
name = "已支付"
def pay(self, order: "Order") -> None:
raise InvalidOperationError("订单已支付,请勿重复支付")
def ship(self, order: "Order") -> None:
print("[发货] 处理发货...")
order.shipped_at = datetime.now()
order.set_state(ShippedState())
print("[+] 已发货")
def confirm(self, order: "Order") -> None:
self._invalid_operation("确认收货")
def cancel(self, order: "Order") -> None:
print("[取消] 取消订单,处理退款...")
order._process_refund()
order.cancelled_at = datetime.now()
order.set_state(CancelledState())
print("[+] 订单已取消,已退款")
已支付状态可以发货或取消,但取消时要退款。
2.2.3 已发货状态
python
class ShippedState(OrderState):
"""已发货状态"""
name = "已发货"
def pay(self, order: "Order") -> None:
self._invalid_operation("支付")
def ship(self, order: "Order") -> None:
raise InvalidOperationError("订单已发货")
def confirm(self, order: "Order") -> None:
print("[确认] 确认收货...")
order.completed_at = datetime.now()
order.set_state(CompletedState())
print("[+] 订单完成")
def cancel(self, order: "Order") -> None:
raise InvalidOperationError("订单已发货,无法取消,请申请退货")
2.2.4 已完成和已取消状态
python
class CompletedState(OrderState):
"""已完成状态"""
name = "已完成"
def pay(self, order: "Order") -> None:
self._invalid_operation("支付")
def ship(self, order: "Order") -> None:
self._invalid_operation("发货")
def confirm(self, order: "Order") -> None:
raise InvalidOperationError("订单已完成")
def cancel(self, order: "Order") -> None:
raise InvalidOperationError("订单已完成,无法取消")
class CancelledState(OrderState):
"""已取消状态(终态)"""
name = "已取消"
def pay(self, order: "Order") -> None:
raise InvalidOperationError("订单已取消")
def ship(self, order: "Order") -> None:
raise InvalidOperationError("订单已取消")
def confirm(self, order: "Order") -> None:
raise InvalidOperationError("订单已取消")
def cancel(self, order: "Order") -> None:
raise InvalidOperationError("订单已取消")
这两个是终态,所有操作都不允许。
2.3 订单上下文类
代码来自 order.py:
python
from datetime import datetime
from typing import Optional
from order_states import OrderState, PendingState
class Order:
"""订单(上下文)"""
def __init__(self, order_id: str, amount: float):
self.order_id = order_id
self.amount = amount
self.created_at = datetime.now()
self.paid_at: Optional[datetime] = None
self.shipped_at: Optional[datetime] = None
self.completed_at: Optional[datetime] = None
self.cancelled_at: Optional[datetime] = None
# 初始状态
self._state: OrderState = PendingState()
@property
def status(self) -> str:
return self._state.name
def set_state(self, state: OrderState) -> None:
"""切换状态"""
old_state = self._state.name
self._state = state
print(f" [状态转换] {old_state} → {state.name}")
# 委托给状态对象处理
def pay(self) -> None:
self._state.pay(self)
def ship(self) -> None:
self._state.ship(self)
def confirm(self) -> None:
self._state.confirm(self)
def cancel(self) -> None:
self._state.cancel(self)
def _process_refund(self) -> None:
"""处理退款"""
print(f" [退款] 退款 ¥{self.amount}")
def __str__(self) -> str:
return f"Order({self.order_id}, ¥{self.amount}, {self.status})"
关键点:Order 类把所有操作都委托给当前状态对象处理。
2.4 使用示例
代码来自 main.py:
python
from order import Order
from order_states import InvalidOperationError
# 创建订单
order = Order("ORD001", 299.00)
print(f"[创建] 创建订单: {order}\n")
# 支付
order.pay()
print(f"[当前] {order}\n")
# 发货
order.ship()
print(f"[当前] {order}\n")
# 确认收货
order.confirm()
print(f"[当前] {order}\n")
# 尝试非法操作
try:
order.cancel()
except InvalidOperationError as e:
print(f"[x] 操作失败: {e}")
输出:
[创建] 创建订单: Order(ORD001, ¥299.0, 待支付)
[支付] 处理支付...
[状态转换] 待支付 → 已支付
[+] 支付成功
[当前] Order(ORD001, ¥299.0, 已支付)
[发货] 处理发货...
[状态转换] 已支付 → 已发货
[+] 已发货
[当前] Order(ORD001, ¥299.0, 已发货)
[确认] 确认收货...
[状态转换] 已发货 → 已完成
[+] 订单完成
[当前] Order(ORD001, ¥299.0, 已完成)
[x] 操作失败: 订单已完成,无法取消
看到没?每个状态的行为都很清晰,状态转换也一目了然。
三、使用transitions库
手写状态类有点繁琐,Python 有个很好用的状态机库 transitions。
3.1 安装和基本用法
bash
pip install transitions
代码来自 order_with_transitions.py:
python
from transitions import Machine
from datetime import datetime
class Order:
"""订单状态机"""
# 定义状态
states = ['pending', 'paid', 'shipped', 'completed', 'cancelled']
def __init__(self, order_id: str, amount: float):
self.order_id = order_id
self.amount = amount
self.created_at = datetime.now()
# 初始化状态机
self.machine = Machine(
model=self,
states=Order.states,
initial='pending',
auto_transitions=False, # 禁用自动转换
send_event=True, # 回调函数接收事件对象
)
# 定义转换
self.machine.add_transition(
trigger='pay', # 触发方法名
source='pending', # 源状态
dest='paid', # 目标状态
before='_before_pay', # 转换前回调
after='_after_pay' # 转换后回调
)
self.machine.add_transition(
trigger='ship',
source='paid',
dest='shipped',
after='_after_ship'
)
self.machine.add_transition(
trigger='confirm',
source='shipped',
dest='completed',
after='_after_confirm'
)
self.machine.add_transition(
trigger='cancel',
source='pending',
dest='cancelled',
after='_after_cancel'
)
self.machine.add_transition(
trigger='cancel',
source='paid',
dest='cancelled',
before='_process_refund',
after='_after_cancel'
)
# ========== 回调函数 ==========
def _before_pay(self, event):
print(f"[支付] 处理支付: 订单 {self.order_id}")
def _after_pay(self, event):
self.paid_at = datetime.now()
print(f"[+] 支付成功")
def _after_ship(self, event):
self.shipped_at = datetime.now()
print(f"[+] 已发货")
def _after_confirm(self, event):
self.completed_at = datetime.now()
print(f"[+] 订单完成")
def _after_cancel(self, event):
self.cancelled_at = datetime.now()
print(f"[+] 订单已取消")
def _process_refund(self, event):
print(f"[退款] 处理退款: ¥{self.amount}")
使用起来和之前一样:
python
order = Order("ORD001", 299.00)
print(f"[初始] 初始状态: {order.state}")
order.pay()
print(f"[当前] 当前状态: {order.state}")
order.ship()
print(f"[当前] 当前状态: {order.state}")
# 检查是否可以执行某操作
print(f"\n[检查] 可以取消吗?{order.may_cancel()}")
print(f"[检查] 可以确认吗?{order.may_confirm()}")
order.confirm()
print(f"[当前] 当前状态: {order.state}")
transitions 库自动给我们生成了 may_xxx() 方法来检查操作是否允许。
3.2 带条件的转换
代码来自 order_with_conditions.py:
python
from transitions import Machine
class Order:
states = ['pending', 'paid', 'shipped', 'completed', 'cancelled']
def __init__(self, order_id: str, amount: float):
self.order_id = order_id
self.amount = amount
self.is_vip = False
self.stock_available = True
self.machine = Machine(
model=self,
states=Order.states,
initial='pending'
)
# 带条件的转换
self.machine.add_transition(
trigger='pay',
source='pending',
dest='paid',
conditions=['_has_stock', '_payment_valid'] # 所有条件都满足才转换
)
# 根据条件转到不同状态
self.machine.add_transition(
trigger='ship',
source='paid',
dest='shipped',
conditions='_can_ship'
)
# unless: 条件不满足时才转换
self.machine.add_transition(
trigger='cancel',
source='pending',
dest='cancelled',
unless='_is_vip_order' # 非VIP订单才能直接取消
)
# ========== 条件函数 ==========
def _has_stock(self):
"""检查库存"""
print(" [检查] 检查库存...")
return self.stock_available
def _payment_valid(self):
"""验证支付"""
print(" [检查] 验证支付...")
return True
def _can_ship(self):
"""是否可发货"""
return True
def _is_vip_order(self):
"""是否VIP订单"""
return self.is_vip
条件函数返回 True 才会触发转换,这样可以实现复杂的业务规则。
3.3 状态图可视化
transitions 还支持生成状态图,代码来自 visualize_states.py:
python
# 安装 graphviz: pip install graphviz
from transitions.extensions import GraphMachine
class Order:
states = ['pending', 'paid', 'shipped', 'completed', 'cancelled']
def __init__(self):
# 使用 GraphMachine 代替 Machine
self.machine = GraphMachine(
model=self,
states=Order.states,
initial='pending',
show_conditions=True,
show_state_attributes=True
)
self.machine.add_transition('pay', 'pending', 'paid')
self.machine.add_transition('ship', 'paid', 'shipped')
self.machine.add_transition('confirm', 'shipped', 'completed')
self.machine.add_transition('cancel', 'pending', 'cancelled')
self.machine.add_transition('cancel', 'paid', 'cancelled')
order = Order()
# 生成状态图
order.get_graph().draw('order_state.png', prog='dot')
print("[+] 状态图已生成: order_state.png")
这会生成一个漂亮的状态转换图,方便理解和文档化。
四、FastAPI订单状态机实战
来构建一个生产级的订单状态机系统。
4.1 项目结构
order_system/
├── main.py
├── models/
│ ├── __init__.py
│ └── order.py
├── schemas/
│ ├── __init__.py
│ └── order.py
├── state_machines/
│ ├── __init__.py
│ └── order_state_machine.py
├── services/
│ ├── __init__.py
│ └── order_service.py
└── repositories/
├── __init__.py
└── order_repository.py
4.2 状态机定义
代码来自 state_machines/order_state_machine.py:
python
from transitions import Machine
from typing import Optional, Callable, List
from datetime import datetime
from enum import Enum
class OrderStatus(str, Enum):
"""订单状态枚举"""
PENDING = "pending"
PAID = "paid"
SHIPPED = "shipped"
COMPLETED = "completed"
CANCELLED = "cancelled"
REFUNDING = "refunding"
REFUNDED = "refunded"
class OrderStateMachine:
"""订单状态机"""
states = [s.value for s in OrderStatus]
# 转换规则配置
transitions = [
# 支付
{'trigger': 'pay', 'source': OrderStatus.PENDING.value,
'dest': OrderStatus.PAID.value, 'conditions': '_can_pay'},
# 发货
{'trigger': 'ship', 'source': OrderStatus.PAID.value,
'dest': OrderStatus.SHIPPED.value},
# 确认收货
{'trigger': 'confirm', 'source': OrderStatus.SHIPPED.value,
'dest': OrderStatus.COMPLETED.value},
# 取消(待支付)
{'trigger': 'cancel', 'source': OrderStatus.PENDING.value,
'dest': OrderStatus.CANCELLED.value},
# 取消(已支付)-> 走退款流程
{'trigger': 'cancel', 'source': OrderStatus.PAID.value,
'dest': OrderStatus.REFUNDING.value},
# 退款完成
{'trigger': 'refund_complete', 'source': OrderStatus.REFUNDING.value,
'dest': OrderStatus.REFUNDED.value},
# 申请退货退款(已发货)
{'trigger': 'request_refund', 'source': OrderStatus.SHIPPED.value,
'dest': OrderStatus.REFUNDING.value},
# 退款完成后标记取消
{'trigger': 'finalize_cancel', 'source': OrderStatus.REFUNDED.value,
'dest': OrderStatus.CANCELLED.value},
]
def __init__(
self,
order_id: str,
initial_state: str = OrderStatus.PENDING.value,
on_state_change: Optional[Callable] = None
):
self.order_id = order_id
self.on_state_change = on_state_change
self.transition_history: List[dict] = []
self.machine = Machine(
model=self,
states=self.states,
transitions=self.transitions,
initial=initial_state,
auto_transitions=False,
after_state_change='_on_state_changed'
)
def _can_pay(self) -> bool:
"""支付条件检查"""
# 实际项目中可能检查:库存、价格变化等
return True
def _on_state_changed(self):
"""状态变更回调"""
record = {
'order_id': self.order_id,
'to_state': self.state,
'timestamp': datetime.now().isoformat()
}
self.transition_history.append(record)
if self.on_state_change:
self.on_state_change(self.order_id, self.state)
def get_available_actions(self) -> List[str]:
"""获取当前状态可用的操作"""
return [t.name for t in self.machine.get_triggers(self.state)]
def can_transition_to(self, target_state: str) -> bool:
"""检查是否可以转换到目标状态"""
for trigger in self.machine.get_triggers(self.state):
transitions = self.machine.get_transitions(trigger, self.state)
for t in transitions:
if t.dest == target_state:
return True
return False
4.3 数据模型
代码来自 models/order.py:
python
from datetime import datetime
from typing import Optional
from pydantic import BaseModel
class Order(BaseModel):
"""订单模型"""
id: str
user_id: int
items: list
amount: float
status: str
created_at: datetime
updated_at: Optional[datetime] = None
paid_at: Optional[datetime] = None
shipped_at: Optional[datetime] = None
completed_at: Optional[datetime] = None
cancelled_at: Optional[datetime] = None
class Config:
from_attributes = True
代码来自 schemas/order.py:
python
from pydantic import BaseModel
from typing import List, Optional
from datetime import datetime
class OrderCreate(BaseModel):
"""创建订单请求"""
user_id: int
items: list
amount: float
class OrderResponse(BaseModel):
"""订单响应"""
id: str
user_id: int
amount: float
status: str
available_actions: List[str]
created_at: datetime
class OrderActionResponse(BaseModel):
"""订单操作响应"""
order_id: str
action: str
old_status: str
new_status: str
message: str
available_actions: List[str]
4.4 订单服务
代码来自 services/order_service.py:
python
from typing import Optional, List
from fastapi import HTTPException, status
from datetime import datetime
from models.order import Order
from schemas.order import OrderCreate, OrderResponse, OrderActionResponse
from state_machines.order_state_machine import OrderStateMachine, OrderStatus
from repositories.order_repository import OrderRepository
class OrderService:
"""订单服务"""
def __init__(self, order_repo: OrderRepository):
self.order_repo = order_repo
def create_order(self, data: OrderCreate) -> OrderResponse:
"""创建订单"""
order = Order(
id=self._generate_order_id(),
user_id=data.user_id,
items=data.items,
amount=data.amount,
status=OrderStatus.PENDING.value,
created_at=datetime.now()
)
order = self.order_repo.add(order)
return self._to_response(order)
def get_order(self, order_id: str) -> OrderResponse:
"""获取订单"""
order = self._get_order_or_404(order_id)
return self._to_response(order)
def pay_order(self, order_id: str) -> OrderActionResponse:
"""支付订单"""
return self._execute_action(order_id, 'pay', "支付成功")
def ship_order(self, order_id: str) -> OrderActionResponse:
"""发货"""
return self._execute_action(order_id, 'ship', "发货成功")
def confirm_order(self, order_id: str) -> OrderActionResponse:
"""确认收货"""
return self._execute_action(order_id, 'confirm', "确认收货成功")
def cancel_order(self, order_id: str) -> OrderActionResponse:
"""取消订单"""
return self._execute_action(order_id, 'cancel', "订单已取消")
def get_available_actions(self, order_id: str) -> List[str]:
"""获取可用操作"""
order = self._get_order_or_404(order_id)
sm = self._get_state_machine(order)
return sm.get_available_actions()
# ========== 私有方法 ==========
def _execute_action(
self,
order_id: str,
action: str,
success_message: str
) -> OrderActionResponse:
"""执行状态转换"""
order = self._get_order_or_404(order_id)
sm = self._get_state_machine(order)
# 检查是否可以执行操作
trigger_method = getattr(sm, f'may_{action}', None)
if trigger_method and not trigger_method():
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"当前状态 [{order.status}] 不支持操作 [{action}]"
)
old_status = order.status
# 执行状态转换
try:
getattr(sm, action)()
except Exception as e:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=str(e)
)
# 更新数据库
order.status = sm.state
order.updated_at = datetime.now()
self.order_repo.update(order)
return OrderActionResponse(
order_id=order_id,
action=action,
old_status=old_status,
new_status=sm.state,
message=success_message,
available_actions=sm.get_available_actions()
)
def _get_order_or_404(self, order_id: str) -> Order:
order = self.order_repo.get_by_id(order_id)
if not order:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail="订单不存在"
)
return order
def _get_state_machine(self, order: Order) -> OrderStateMachine:
return OrderStateMachine(
order_id=order.id,
initial_state=order.status
)
def _to_response(self, order: Order) -> OrderResponse:
sm = self._get_state_machine(order)
return OrderResponse(
id=order.id,
user_id=order.user_id,
amount=order.amount,
status=order.status,
available_actions=sm.get_available_actions(),
created_at=order.created_at
)
def _generate_order_id(self) -> str:
"""生成订单ID"""
import uuid
return f"ORD{uuid.uuid4().hex[:10].upper()}"
4.5 API 路由
代码来自 main.py:
python
from fastapi import FastAPI, Depends
from typing import List
from services.order_service import OrderService
from schemas.order import OrderCreate, OrderResponse, OrderActionResponse
from repositories.order_repository import OrderRepository
# 依赖注入
def get_order_service():
repo = OrderRepository()
return OrderService(repo)
app = FastAPI(title="订单状态机示例")
@app.post("/orders", response_model=OrderResponse)
def create_order(
data: OrderCreate,
service: OrderService = Depends(get_order_service)
):
"""创建订单"""
return service.create_order(data)
@app.get("/orders/{order_id}", response_model=OrderResponse)
def get_order(
order_id: str,
service: OrderService = Depends(get_order_service)
):
"""获取订单详情"""
return service.get_order(order_id)
@app.get("/orders/{order_id}/actions", response_model=List[str])
def get_available_actions(
order_id: str,
service: OrderService = Depends(get_order_service)
):
"""获取订单可用操作"""
return service.get_available_actions(order_id)
@app.post("/orders/{order_id}/pay", response_model=OrderActionResponse)
def pay_order(
order_id: str,
service: OrderService = Depends(get_order_service)
):
"""支付订单"""
return service.pay_order(order_id)
@app.post("/orders/{order_id}/ship", response_model=OrderActionResponse)
def ship_order(
order_id: str,
service: OrderService = Depends(get_order_service)
):
"""发货"""
return service.ship_order(order_id)
@app.post("/orders/{order_id}/confirm", response_model=OrderActionResponse)
def confirm_order(
order_id: str,
service: OrderService = Depends(get_order_service)
):
"""确认收货"""
return service.confirm_order(order_id)
@app.post("/orders/{order_id}/cancel", response_model=OrderActionResponse)
def cancel_order(
order_id: str,
service: OrderService = Depends(get_order_service)
):
"""取消订单"""
return service.cancel_order(order_id)
4.6 响应示例
json
// GET /orders/ORD001
{
"id": "ORD001",
"user_id": 1,
"amount": 299.00,
"status": "pending",
"available_actions": ["pay", "cancel"],
"created_at": "2024-01-15T10:30:00"
}
// POST /orders/ORD001/pay
{
"order_id": "ORD001",
"action": "pay",
"old_status": "pending",
"new_status": "paid",
"message": "支付成功",
"available_actions": ["ship", "cancel"]
}
看到没?通过状态机,我们可以动态地告诉前端当前订单能做哪些操作。
五、状态模式vs策略模式
这两个模式经常被混淆,因为结构很像。
| 方面 | 状态模式 | 策略模式 |
|---|---|---|
| 目的 | 管理对象的状态转换 | 封装可互换的算法 |
| 状态/策略数量 | 通常固定,和业务状态对应 | 可能很多,按需添加 |
| 切换时机 | 运行时自动切换(状态转换) | 初始化时或运行时手动切换 |
| 切换者 | 状态对象自己决定下一个状态 | 客户端或上下文决定用哪个策略 |
| 典型场景 | 订单状态、工作流、TCP连接 |
支付方式、排序算法、压缩算法 |
代码对比:
python
# 状态模式:状态决定下一个状态
class PaidState:
def ship(self, order):
order.set_state(ShippedState()) # 状态自己决定转换
# 策略模式:外部决定使用哪个策略
class PaymentService:
def pay(self, strategy: PaymentStrategy):
strategy.pay() # 调用方决定用什么策略
简单说:状态模式关注状态转换 ,策略模式关注算法替换。
六、总结
状态模式的核心是把状态相关的行为封装到独立的状态类中,让状态转换变得清晰可控。
什么时候用:
- 对象行为取决于状态,且状态会在运行时改变
- 代码中有大量与状态相关的条件判断
- 状态转换规则复杂,需要清晰管理
实现方式对比:
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 手写状态类 | 完全控制,逻辑清晰 | 代码量大 | 状态少,逻辑复杂 |
transitions 库 |
配置式,支持可视化 | 需要学习库 | 状态多,规则复杂 |
| 状态机框架 | 功能强大,持久化 | 过于重量级 | 企业级应用 |
关键要点总结:
| 概念 | 说明 | 适用场景 | 注意事项 |
|---|---|---|---|
| 状态封装 | 每个状态独立的类 | 状态行为差异大 | 避免状态类过多 |
| 状态转换 | 由状态对象控制 | 转换规则复杂 | 防止循环依赖 |
| 上下文对象 | 委托给状态处理 | 所有模式通用 | 保持接口一致 |
| 条件转换 | 带条件的状态切换 | 业务规则复杂 | 条件函数要简单 |
和其他模式配合:
- 状态可以用单例(无状态的状态对象)
- 状态创建可以用工厂模式
- 状态转换可以触发观察者通知
下一步 :下一篇可以聊聊适配器模式 ,在对接第三方 API、兼容旧系统时特别有用。
热门专栏推荐
- Agent小册
- 服务器部署
- Java基础合集
- Python基础合集
- Go基础合集
- 大数据合集
- 前端小册
- 数据库合集
- Redis 合集
- Spring 全家桶
- 微服务全家桶
- 数据结构与算法合集
- 设计模式小册
- 消息队列合集
等等等还有许多优秀的合集在主页等着大家的光顾,感谢大家的支持
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😊
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🙏
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🌟