订单状态流转/播放器控制/游戏角色行为…一个模式搞定所有状态驱动型逻辑!
假设你在开发一个外卖App,订单有以下状态:
等待接单
已接单
配送中
已完成
已取消
每个状态下:
传统实现方式(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;
// ...其他状态
}
}
}
痛点:
核心思想: 允许对象在其内部状态改变时改变它的行为,对象看起来像是修改了它的类。
三个关键角色:
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);
}
// 等待接单状态
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
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);
}
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),
),
);
}
}
// 状态接口
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();
}
});
},
)
// 游戏角色状态
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();
}
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;
}
将状态模式与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();
何时使用状态模式:
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));
}
});
}
特性 | 状态模式 | 策略模式 |
---|---|---|
目的 | 管理状态转换和状态相关行为 | 封装可互换的算法 |
状态知晓 | 状态知道其他状态 | 策略相互独立 |
状态改变 | 状态可改变上下文的状态 | 策略通常不改变上下文 |
典型应用 | 订单状态、播放器控制 | 支付策略、排序算法 |
// 基础状态
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) {
// 处理准备命令
}
}
}
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();
}
}
}
总结:状态模式是你的行为变身器
设计启示: 当你的对象需要根据状态改变行为,且状态转换逻辑复杂时,状态模式是优雅的解决方案!