狀態模式 - 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;// ...其他狀態}}
}

痛點:

  • 代碼臃腫,一個類包含所有狀態的邏輯
  • 添加新狀態需要修改現有類
  • 狀態轉換邏輯分散在各處
  • 違反開閉原則(對擴展開放,對修改關閉)

狀態模式解決方案

核心思想: 允許對象在其內部狀態改變時改變它的行為,對象看起來像是修改了它的類。

三個關鍵角色:

  1. 上下文(Context): 維護當前狀態,定義狀態接口
  2. 抽象狀態(State): 定義狀態接口
  3. 具體狀態(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();

狀態模式最佳實踐

  1. 何時使用狀態模式:

    • 對象的行為取決于它的狀態
    • 狀態數量較多(>3)
    • 狀態轉換邏輯復雜
    • 需要避免使用大量的條件語句
  2. 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 => // 從當前狀態推斷類型
    }
    
  3. 狀態轉換管理:

    // 狀態轉換表
    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));}
    }
    
  4. 狀態持久化:

    // 保存狀態到本地
    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狀態管理

🎮 設計啟示: 當你的對象需要根據狀態改變行為,且狀態轉換邏輯復雜時,狀態模式是優雅的解決方案!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/87304.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87304.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/87304.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據庫9:數據庫字符編碼調整與校隊(排序)規則

一.常用字符編碼 1.ASCII編碼 用一個字節表示一個字符 2.ANSI編碼 每個國家為了顯示本國的語言而對ASCII碼進行了拓展 用兩個字節表示一個漢字&#xff0c;中國的ANSI編碼是GB2312編碼&#xff08;簡體&#xff09;&#xff0c;日本的ANSI編碼是JIS編碼&#xff0c;臺灣的A…

人臉活體識別4:Android實現人臉眨眼 張嘴 點頭 搖頭識別(可實時檢測)

人臉活體識別4&#xff1a;Android實現人臉眨眼 張嘴 點頭 搖頭識別(可實時檢測) 目錄 人臉活體識別4&#xff1a;Android實現人臉眨眼 張嘴 點頭 搖頭識別(可實時檢測) 1. 前言 2.人臉活體識別方法 &#xff08;1&#xff09;基于人臉動作的檢測?? &#xff08;2&…

DAY1-Linux操作系統1

文章參考【黑馬程序員Python教程_600集Python從入門到精通教程&#xff08;懂中文就能學會&#xff09;】 https://www.bilibili.com/video/BV1ex411x7Em/?p40&share_sourcecopy_web&vd_source263bbee2ddeb835c3ab6d9d3c80e0f7c 一.常用命令簡單介紹 使用軟件 虛擬機…

第十二節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 - 兩種權限控制方式(附前后端代碼)

Vben5 系列文章目錄 ?? 基礎篇 ? 第一節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 ? 第二節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入門 - Python Flask 后端開發詳解(附源碼) ? 第三節:Vben Admin 最新 v5.0 (vben5) + Python Flask 快速入…

華為云Flexus+DeepSeek征文 | 華為云 ModelArts Studio 賦能 AI 法務:合同審查與法律文件生成系統

一、引言 在法律行業數字化轉型的浪潮中&#xff0c;AI 技術正重塑法律服務的流程與效率。本文介紹如何利用華為云 ModelArts Studio 構建一套完整的 AI 法務系統&#xff0c;實現合同審查、法律文件生成、法律咨詢與風險識別的智能化解決方案。 二、系統架構設計 &#xff0…

SQL的底層邏輯解析

SQL的底層邏輯涉及數據庫管理系統(DBMS)如何解析、優化和執行SQL查詢&#xff0c;主要包括以下幾個層面&#xff1a; ?查詢處理流程? 解析器(Parser)&#xff1a;將SQL語句轉換為語法樹查詢優化器(Optimizer)&#xff1a;基于統計信息和成本模型生成最優執行計劃執行引擎(Exe…

深入剖析AI大模型:PyTorch 技術詳解

今天說一說PyTorch。作為一名python程序員&#xff0c;可能對它了解起來還是很快的。在人工智能浪潮席卷全球的當下&#xff0c;深度學習作為其核心技術&#xff0c;被廣泛應用于圖像識別、自然語言處理、語音識別等多個領域。而在深度學習的開發框架中&#xff0c;PyTorch 憑借…

物聯網架構:定義、解釋和實例

物聯網&#xff08;IoT&#xff09;架構是一個復雜且多維度的概念&#xff0c;構成了物聯網系統的核心框架。它是勾勒物聯網設備、應用程序和技術如何相互交互以實現預期功能的藍圖。物聯網架構并非 “一刀切” 的模型&#xff0c;而是會根據相關物聯網系統的具體需求而有所不同…

拿到一臺新服務器,怎么跑AI項目

公司新采購一臺AI服務器&#xff0c;花大本錢裝了個A6000顯卡&#xff0c;今天來記錄下新服務的使用步驟。 1、查看系統。 這臺服務器預裝了Ubuntu20.04系統。 lsb_release -a 查看下cpu、內存情況 top 看著還行。 再看下硬盤空間 df -h 空間不算小&#xff0c;2T。 2、…

IO--進程實操

1.創建一個進程扇 #include <051head.h> int main(int argc, const char *argv[]) {pid_t pid;for(int i0;i<4;i){pidfork();if(pid-1) //父進程{ERRLOG("fork error..\n");} else if(pid0) //這是子進程{ …

模型預測控制(MPC)概覽

模型預測控制&#xff08;Model Predictive Control, MPC&#xff09; 一、理論基礎與發展脈絡 1. 歷史起源 20世紀70年代起源于工業過程控制&#xff08;如化工領域的動態矩陣控制DMC、模型算法控制MAC&#xff09;&#xff0c;由Richalet、Mehra等學者提出&#xff0c;核心…

Python初體驗:從入門到實踐

Python無疑是開啟編程世界大門的絕佳鑰匙。今天,就讓我們一起踏上Python的學習之旅。 #01 編寫第一個Python程序 環境搭建好之后,上節已經編寫了第一個Python程序。現在就好比,我們已經準備好了廚房和食材,要開始做第一道菜了。啟動Jupyter后,在Jupyter中新建一個文件,…

【數字后端】- 什么是AOI、OAI cell?它們后面數字的含義

是什么&#xff1f; 不管是在DC綜合階段&#xff0c;還是在PR階段&#xff0c;嘗嘗會出現OAI、AOI組合邏輯單元的身影。因為它們可以通過巧妙的串聯和并聯晶體管非常高效地實現組合邏輯&#xff0c;因此在VLSI設計中非常常用。但是它們也是高pin密度單元&#xff0c;也可能會造…

MQTTServer服務器根據MQTTClient客戶端已訂閱的主題推送 分發消息

網絡讀卡器介紹&#xff1a;https://item.taobao.com/item.htm?ftt&id22173428704&spma21dvs.23580594.0.0.52de2c1bgK3bgZ 本示例使用了MQTTNet插件 C# MQTTNETServer 源碼 using MQTTnet.Client.Receiving; using MQTTnet.Server; using MQTTnet; using System; u…

【seismic unix 合并兩個su文件】

Seismic Unix簡介 Seismic Unix&#xff08;SU&#xff09;是由科羅拉多礦業學院開發的開源地震數據處理軟件包&#xff0c;基于Unix/Linux環境運行。它提供了一系列命令行工具&#xff0c;用于地震數據加載、處理、分析和可視化&#xff0c;支持SEG-Y格式和SU自定義格式。SU廣…

【vmware虛擬機使用】安裝vmware workstations17

安裝vmware17 本章學習目標VMware虛擬機簡介開始實操下載VMware workstation虛擬機安裝虛擬機配置虛擬機網絡 總結 本章學習目標 1.安裝vmware workstation虛擬機 2.自定義配置虛擬機網絡&#xff0c;避免網絡沖突 VMware虛擬機簡介 ? VMware的核心是Hypervisor&#xff0…

QT6 源(147)模型視圖架構里的表格窗體 QTableWidget 的范例代碼舉例,以及其條目 QTableWidgetItem 類型的源代碼。

&#xff08;1&#xff09;先用一個簡單的例子&#xff0c;學習一下本類里的成員函數的使用。生成如下圖的界面&#xff0c;表格窗體與初始數據&#xff1a; 查看其 ui_widget . h 文件 &#xff0c;里面的將是最標準的表格窗體的使用代碼 &#xff1a; #ifndef UI_WIDGET_H #…

URL時間戳參數深度解析:緩存破壞與前端優化的前世今生

&#x1f50d; URL時間戳參數深度解析&#xff1a;緩存破壞與前端優化的前世今生 在日常的Web開發中&#xff0c;你是否注意到很多接口URL后面都會帶有一個時間戳參數&#xff1f;比如 xxx/getMsg?_1751413509056。這個看似簡單的參數背后&#xff0c;卻隱藏著前端緩存策略、性…

分布式鎖實現方式:基于Redis的分布式鎖實現(Spring Boot + Redis)

Redis實現分布式鎖的原理 Redis分布式鎖基于其單線程執行命令的特性&#xff0c;通過原子操作實現多節點間的互斥訪問。下面從原理、實現、問題及優化四個方面詳細解析&#xff1a; 1.原子性與互斥性 Redis分布式鎖的核心是原子性操作&#xff1a; 獲取鎖&#xff1a;使用SE…

linux升級降級內核實驗

?實驗環境 vmware workstation 17 centos7.9 下載鏈接&#xff1a; https://vault.centos.org/7.9.2009/isos/x86_64/ ubuntu24.04 下載鏈接&#xff1a; https://old-releases.ubuntu.com/releases/24.04/ ?實驗目的 為了解決日常環境部署中某些驅動軟件依賴特定內…