状态模式 - Flutter中的状态变身术,让对象随“状态“自由切换行为!
订单状态流转/播放器控制/游戏角色行为…一个模式搞定所有状态驱动型逻辑!
经典场景:订单状态管理
假设你在开发一个外卖App,订单有以下状态:
等待接单
已接单
配送中
已完成
已取消
每个状态下:
- 显示的UI不同
- 可执行的操作不同
- 状态转换规则不同
传统实现方式(switch-case地狱):
class Order {String state = 'waiting'; // 状态字段Widget buildUI() {switch(state) {case 'waiting':return _buildWaitingUI();case 'accepted':return _buildAcceptedUI();// ...其他状态}}void performAction(String action) {switch(state) {case 'waiting':if (action == 'accept') {state = 'accepted';// 执行接单逻辑}break;case 'accepted':if (action == 'pickup') {state = 'delivering';// 执行取货逻辑}break;// ...其他状态}}
}
痛点:
- 代码臃肿,一个类包含所有状态的逻辑
- 添加新状态需要修改现有类
- 状态转换逻辑分散在各处
- 违反开闭原则(对扩展开放,对修改关闭)
状态模式解决方案
核心思想: 允许对象在其内部状态改变时改变它的行为,对象看起来像是修改了它的类。
三个关键角色:
- 上下文(Context): 维护当前状态,定义状态接口
- 抽象状态(State): 定义状态接口
- 具体状态(ConcreteState): 实现特定状态的行为
Flutter订单状态模式实现
1. 定义状态接口
abstract class OrderState {Widget buildUI(OrderContext context);void acceptOrder(OrderContext context);void pickUp(OrderContext context);void deliver(OrderContext context);void complete(OrderContext context);void cancel(OrderContext context);
}
2. 实现具体状态类
// 等待接单状态
class WaitingState implements OrderState { Widget buildUI(OrderContext context) {return Column(children: [Text('等待商家接单...', style: TextStyle(color: Colors.orange)),ElevatedButton(onPressed: () => context.acceptOrder(),child: Text('接单'),)],);}void acceptOrder(OrderContext context) {print('订单已接单');context.changeState(AcceptedState());}// 其他方法在当前状态下不适用void pickUp(OrderContext context) => _showError('接单后才能取货');void deliver(OrderContext context) => _showError('请先取货');void complete(OrderContext context) => _showError('订单未完成');void cancel(OrderContext context) {print('订单已取消');context.changeState(CanceledState());}void _showError(String msg) => print('操作失败: $msg');
}// 已接单状态
class AcceptedState implements OrderState { Widget buildUI(OrderContext context) {return Column(children: [Text('商家已接单', style: TextStyle(color: Colors.green)),ElevatedButton(onPressed: () => context.pickUp(),child: Text('取货'),)],);}void pickUp(OrderContext context) {print('商品已取货');context.changeState(DeliveringState());}// ...其他方法实现类似
}// 其他状态类:DeliveringState, CompletedState, CanceledState
3. 创建上下文类
class OrderContext {OrderState _state = WaitingState();void changeState(OrderState newState) {_state = newState;}// 委托所有操作给当前状态Widget buildUI() => _state.buildUI(this);void acceptOrder() => _state.acceptOrder(this);void pickUp() => _state.pickUp(this);void deliver() => _state.deliver(this);void complete() => _state.complete(this);void cancel() => _state.cancel(this);
}
4. 在Flutter组件中使用
class OrderScreen extends StatefulWidget { _OrderScreenState createState() => _OrderScreenState();
}class _OrderScreenState extends State<OrderScreen> {final OrderContext orderContext = OrderContext(); Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text('订单详情')),body: Center(child: orderContext.buildUI(),),floatingActionButton: FloatingActionButton(onPressed: () => orderContext.cancel(),tooltip: '取消订单',child: Icon(Icons.cancel),),);}
}
Flutter中的实际应用场景
场景1:媒体播放器控制
// 状态接口
abstract class PlayerState {void play(PlayerContext context);void pause(PlayerContext context);void stop(PlayerContext context);IconData get icon;
}// 具体状态
class PlayingState implements PlayerState { void play(PlayerContext context) => print('已在播放中'); void pause(PlayerContext context) => context.changeState(PausedState()); void stop(PlayerContext context) => context.changeState(StoppedState()); IconData get icon => Icons.pause;
}class PausedState implements PlayerState { void play(PlayerContext context) => context.changeState(PlayingState()); void pause(PlayerContext context) => print('已暂停'); void stop(PlayerContext context) => context.changeState(StoppedState()); IconData get icon => Icons.play_arrow;
}// 上下文
class PlayerContext {PlayerState _state = StoppedState();void changeState(PlayerState state) => _state = state;IconData get icon => _state.icon;void play() => _state.play(this);void pause() => _state.pause(this);void stop() => _state.stop(this);
}// 在UI中使用
IconButton(icon: Icon(playerContext.icon),onPressed: () {setState(() {if (playerContext is PlayingState) {playerContext.pause();} else {playerContext.play();}});},
)
场景2:游戏角色状态
// 游戏角色状态
abstract class CharacterState {void move();void attack();void takeDamage();String get animation;
}// 具体状态
class IdleState implements CharacterState { void move() => print('开始移动'); void attack() => print('发起攻击'); void takeDamage() => print('受到伤害'); String get animation => 'idle_anim';
}class WalkingState implements CharacterState { void move() => print('继续移动'); void attack() => print('移动中攻击'); void takeDamage() => print('移动中受伤'); String get animation => 'walk_anim';
}// 上下文
class GameCharacter {CharacterState _state = IdleState();void changeState(CharacterState state) => _state = state;void update() {// 游戏循环中更新状态render(_state.animation);}void onMoveCommand() => _state.move();void onAttackCommand() => _state.attack();void onDamage() => _state.takeDamage();
}
场景3:表单验证状态
abstract class FormState {bool validate();void submit();Color get buttonColor;
}class InvalidState implements FormState { bool validate() => false; void submit() => print('表单无效,不能提交'); Color get buttonColor => Colors.grey;
}class ValidState implements FormState { bool validate() => true; void submit() => print('提交表单'); Color get buttonColor => Colors.blue;
}class FormContext {FormState _state = InvalidState();void validateForm(List<String> errors) {_state = errors.isEmpty ? ValidState() : InvalidState();}void submit() => _state.submit();Color get buttonColor => _state.buttonColor;
}
状态模式与Flutter状态管理的结合
将状态模式与Provider结合使用:
// 创建状态提供者
class OrderStateProvider extends ChangeNotifier {OrderContext _orderContext = OrderContext();OrderContext get orderContext => _orderContext;void acceptOrder() {_orderContext.acceptOrder();notifyListeners();}void pickUp() {_orderContext.pickUp();notifyListeners();}// 其他操作...
}// 在顶层注册
void main() {runApp(ChangeNotifierProvider(create: (context) => OrderStateProvider(),child: MyApp(),),);
}// 在组件中使用
Consumer<OrderStateProvider>(builder: (context, provider, child) {return provider.orderContext.buildUI();}
)// 执行操作
context.read<OrderStateProvider>().acceptOrder();
状态模式最佳实践
-
何时使用状态模式:
- 对象的行为取决于它的状态
- 状态数量较多(>3)
- 状态转换逻辑复杂
- 需要避免使用大量的条件语句
-
Flutter特化技巧:
// 使用枚举定义状态类型 enum OrderStateType { waiting, accepted, delivering, completed, canceled }// 状态工厂 OrderState createState(OrderStateType type) {switch(type) {case OrderStateType.waiting: return WaitingState();case OrderStateType.accepted: return AcceptedState();// ...} }// 在上下文中保存状态类型 class OrderContext {OrderStateType get stateType => // 从当前状态推断类型 }
-
状态转换管理:
// 状态转换表 const Map<OrderStateType, Map<String, OrderStateType>> transitions = {OrderStateType.waiting: {'accept': OrderStateType.accepted,'cancel': OrderStateType.canceled,},OrderStateType.accepted: {'pickup': OrderStateType.delivering,'cancel': OrderStateType.canceled,},// ... };// 在上下文中使用 void transition(String action) {final nextStateType = transitions[stateType]?[action];if (nextStateType != null) {changeState(createState(nextStateType));} }
-
状态持久化:
// 保存状态到本地 void saveState() {SharedPreferences.getInstance().then((prefs) {prefs.setString('order_state', _stateType.toString());}); }// 恢复状态 void restoreState() {SharedPreferences.getInstance().then((prefs) {final stateStr = prefs.getString('order_state');if (stateStr != null) {final stateType = OrderStateType.values.firstWhere((e) => e.toString() == stateStr);changeState(createState(stateType));}}); }
状态模式 vs 策略模式
特性 | 状态模式 | 策略模式 |
---|---|---|
目的 | 管理状态转换和状态相关行为 | 封装可互换的算法 |
状态知晓 | 状态知道其他状态 | 策略相互独立 |
状态改变 | 状态可改变上下文的状态 | 策略通常不改变上下文 |
典型应用 | 订单状态、播放器控制 | 支付策略、排序算法 |
状态模式的高级变体
1. 分层状态机
// 基础状态
abstract class BaseState {void handleEvent(Event event);
}// 具体状态可以包含子状态
class DeliveryState implements BaseState {BaseState _currentSubState = PreparingState();void handleEvent(Event event) {_currentSubState.handleEvent(event);// 处理状态转换if (event is PreparedEvent) {_currentSubState = OnTheWayState();}}
}// 子状态
class PreparingState implements BaseState {void handleEvent(Event event) {if (event is PrepareCommand) {// 处理准备命令}}
}
2. 历史状态
class OrderContext {final List<OrderState> _stateHistory = [];OrderState _currentState = WaitingState();void changeState(OrderState newState) {_stateHistory.add(_currentState);_currentState = newState;}void undo() {if (_stateHistory.isNotEmpty) {_currentState = _stateHistory.removeLast();}}
}
总结:状态模式是你的行为变身器
- 核心价值: 将不同状态的行为局部化到各自类中
- Flutter优势:
- 消除庞大的条件语句
- 简化状态转换逻辑
- 符合单一职责原则
- 提高代码可扩展性和可维护性
- 适用场景: 订单系统、游戏角色、媒体播放器、工作流引擎、UI状态管理
🎮 设计启示: 当你的对象需要根据状态改变行为,且状态转换逻辑复杂时,状态模式是优雅的解决方案!