本文目录导读:

在 Laravel 工作流开发中,状态模式确实是核心的底层设计思想,但实际应用中很少直接套用“标准状态模式”的类结构,而是借助 Laravel 特有的工具(如状态机包、Eloquent 事件、管道)来实现更灵活的实现。
核心逻辑:状态模式的定义
标准状态模式允许对象在内部状态改变时改变其行为,这完全符合工作流(Workflow)的需求:
- 每个状态定义允许的转换
- 状态转换时触发业务逻辑
- 对象的行为随当前状态而变化
Laravel 中的实现方案
主流方案:状态机包(如 spatie/laravel-model-states)
这是最接近状态模式的实现:
// 定义状态
class PendingState extends State
{
public function approve(): State
{
$this->performEvent('approve');
return new ApprovedState($this->model);
}
public function reject(): State
{
$this->performEvent('reject');
return new RejectedState($this->model);
}
}
class ApprovedState extends State
{
public function reprocess(): State
{
return new PendingState($this->model);
}
}
// 使用
$order = Order::find(1);
$order->state->transition(new ApprovedState($order));
经典实现:cerbero90/laravel-workflow 或自定义
直接复现 GoF 状态模式的类结构:
// 上下文
class OrderContext
{
private OrderState $state;
public function __construct(Order $order)
{
$this->state = match($order->status) {
'pending' => new PendingState(),
'paid' => new PaidState(),
default => throw new \Exception()
};
}
public function proceed(OrderAction $action): void
{
// 委托给当前状态处理
$this->state->handle($this, $action);
}
public function setState(OrderState $state): void
{
$this->state = $state;
}
}
// 状态接口
interface OrderState
{
public function handle(OrderContext $context, OrderAction $action): void;
}
class PendingState implements OrderState
{
public function handle(OrderContext $context, OrderAction $action): void
{
if ($action->isPay()) {
// 执行业务逻辑
$context->setState(new PaidState());
}
}
}
轻型方案:Eloquent + 策略模式(简易替代)
不严格遵循状态模式,但能实现类似效果:
// Eloquent Model
class Order extends Model
{
protected $states = [
'pending' => PendingHandler::class,
'paid' => PaidHandler::class,
];
// 状态变更验证
protected $validTransitions = [
'pending' => ['paid', 'cancelled'],
'paid' => ['shipped'],
'shipped' => ['delivered'],
];
public function transitionTo(string $newState): void
{
// 检查转换合法性
if (!in_array($newState, $this->validTransitions[$this->status] ?? [])) {
throw new InvalidTransitionException();
}
$this->status = $newState;
$this->save();
// 触发业务逻辑
(new $this->states[$newState]($this))->handle();
}
}
实际项目中的最佳实践
个人推荐的工具栈
- 简单工作流:Eloquent
status字段 +transition()方法 - 复杂工作流:
spatie/laravel-model-states - 业务流程引擎:
symfony/workflow(Laravel 可集成)
关键决策点
| 维度 | 标准状态模式 | Laravel 实用方案 |
|---|---|---|
| 状态数量 | ✅ 2-10 个 | ✅ 任何数量 |
| 转换逻辑复杂性 | 状态越多,类越多 | 配置驱动,易于扩展 |
| 数据持久化 | 需要额外实现 | 天然支持 Eloquent |
| 事件监听 | 需手动实现 | 原生支持 Laravel Events |
| 团队可维护性 | 可能过度工程 | 更适合 Laravel 开发者 |
代码示例(基于 spatie 包)
// app/Models/States/TicketState.php
abstract class TicketState extends State
{
abstract public function statusLabel(): string;
public function assignTo(User $user): void
{
$this->model->assigned_to = $user->id;
$this->model->save();
}
}
// app/Models/States/Pending.php
class Pending extends TicketState
{
public function statusLabel(): string
{
return '待处理';
}
public function startWork(): State
{
// 验证权限
// 记录日志
event(new TicketStarted($this->model));
return new InProgress($this->model);
}
}
// Model
class Ticket extends Model
{
use HasStates;
protected $casts = [
'state' => TicketState::class,
];
public function startWork(): void
{
// 转换状态,自动验证合法性
$this->state->transitionTo(InProgress::class);
}
}
Laravel 工作流在概念上完全使用状态模式,但在实现上:
✅ 推荐使用:
spatie/laravel-model-states(接近标准状态模式)- Eloquent + 自定义状态验证(简易场景)
❌ 不推荐:
- 手动实现完整的 GoF 状态模式代码结构(复杂且不必要)
- 在单个控制器/Service 中写
if/else处理所有状态转换
核心原则:利用 Laravel 生态提供的工具(状态机包、Eloquent、事件),而不是重新发明轮子,这能让你获得状态模式的所有优点(可扩展、行为封装、状态转换可控),同时保持 Laravel 代码的简洁和可维护性。