深入理解設計模式之狀態模式

深入理解設計模式之:狀態模式(State Pattern)

一、什么是狀態模式?

狀態模式(State Pattern)是一種行為型設計模式。它允許一個對象在其內部狀態發生改變時,改變其行為(即表現出不同的行為)。狀態模式將與狀態相關的行為封裝到獨立的狀態類中,并通過狀態切換來改變對象的行為。

核心思想:
將狀態的切換和行為的變化解耦,使得狀態切換變得靈活,代碼結構清晰,易于擴展和維護。


二、狀態模式的應用場景

  • 對象的行為依賴于它的狀態,并且在運行時根據狀態發生改變
  • 代碼中包含大量與狀態相關的條件語句(如 if-else 或 switch-case)
  • 狀態切換頻繁,且狀態行為復雜

常見例子:

  • 工作流引擎(如訂單狀態:待支付、已支付、已發貨、已完成等)
  • TCP 連接狀態(CLOSED、LISTEN、SYN_SENT、ESTABLISHED 等)
  • 游戲角色狀態(待機、攻擊、防御、死亡等)

三、狀態模式的結構

  • Context(環境類):持有當前狀態對象,負責狀態切換
  • State(抽象狀態):定義所有具體狀態的公共接口
  • ConcreteState(具體狀態):實現具體狀態對應的行為

四、UML 類圖

+----------------+        +---------------------+
|    Context     |<>----->|     State           |
+----------------+        +---------------------+
| state: State   |        | + handle()          |
| + setState()   |        +---------------------+
| + request()    |                /_\
+----------------+                 ||+------------------+------------------+|                                     |+---------------------+             +---------------------+| ConcreteStateA      |             | ConcreteStateB      |+---------------------+             +---------------------+| + handle()          |             | + handle()          |+---------------------+             +---------------------+

五、Java 實現代碼示例

1. 抽象狀態接口

public interface State {void handle(Context context);
}

2. 具體狀態類

public class StateA implements State {@Overridepublic void handle(Context context) {System.out.println("當前狀態:A,切換到狀態B");context.setState(new StateB());}
}public class StateB implements State {@Overridepublic void handle(Context context) {System.out.println("當前狀態:B,切換到狀態A");context.setState(new StateA());}
}

3. 環境類

public class Context {private State state;public Context(State state) {this.state = state;}public void setState(State state) {this.state = state;}public void request() {state.handle(this);}
}

4. 客戶端調用

public class Main {public static void main(String[] args) {Context context = new Context(new StateA());context.request(); // 輸出:當前狀態:A,切換到狀態Bcontext.request(); // 輸出:當前狀態:B,切換到狀態Acontext.request(); // 輸出:當前狀態:A,切換到狀態B}
}

六、實際應用案例:訂單狀態流轉

以電商訂單為例,訂單有“待支付”、“已支付”、“已發貨”、“已完成”四種狀態,每種狀態下允許的操作不同。

1. 狀態接口

public interface OrderState {void next(OrderContext ctx);void prev(OrderContext ctx);String getStatus();
}

2. 具體狀態類

public class PendingState implements OrderState {public void next(OrderContext ctx) {ctx.setState(new PaidState());}public void prev(OrderContext ctx) {System.out.println("已是初始狀態,不能回退");}public String getStatus() {return "待支付";}
}public class PaidState implements OrderState {public void next(OrderContext ctx) {ctx.setState(new ShippedState());}public void prev(OrderContext ctx) {ctx.setState(new PendingState());}public String getStatus() {return "已支付";}
}public class ShippedState implements OrderState {public void next(OrderContext ctx) {ctx.setState(new CompletedState());}public void prev(OrderContext ctx) {ctx.setState(new PaidState());}public String getStatus() {return "已發貨";}
}public class CompletedState implements OrderState {public void next(OrderContext ctx) {System.out.println("訂單已完成,不能再前進");}public void prev(OrderContext ctx) {ctx.setState(new ShippedState());}public String getStatus() {return "已完成";}
}

3. 環境類

public class OrderContext {private OrderState state;public OrderContext() {state = new PendingState();}public void setState(OrderState state) {this.state = state;}public void next() {state.next(this);}public void prev() {state.prev(this);}public void printStatus() {System.out.println("當前訂單狀態:" + state.getStatus());}
}

4. 客戶端調用

public class Main {public static void main(String[] args) {OrderContext order = new OrderContext();order.printStatus(); // 待支付order.next();order.printStatus(); // 已支付order.next();order.printStatus(); // 已發貨order.next();order.printStatus(); // 已完成order.next();        // 訂單已完成,不能再前進order.prev();order.printStatus(); // 已發貨}
}

七、狀態模式的優缺點

優點:

  • 狀態切換邏輯清晰,易于擴展和維護
  • 避免大量 if-else 或 switch-case
  • 狀態行為封裝,符合開閉原則

缺點:

  • 狀態類數量可能增多
  • 結構相對復雜

八、總結

狀態模式是處理對象狀態切換和行為變化的經典方案,廣泛應用于工作流、狀態機、游戲開發等場景。掌握狀態模式有助于編寫靈活、可擴展的代碼結構。

建議:

  • 當對象行為依賴于狀態且狀態切換復雜時,優先考慮狀態模式
  • 狀態模式與策略模式、命令模式等常結合使用

如需更多設計模式講解或源碼分析,歡迎留言交流!

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

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

相關文章

Redis的大Key問題如何解決?

大家好&#xff0c;我是鋒哥。今天分享關于【Redis的大Key問題如何解決&#xff1f;】面試題。希望對大家有幫助&#xff1b; Redis的大Key問題如何解決&#xff1f; 1000道 互聯網大廠Java工程師 精選面試題-Java資源分享網 Redis中的“大Key”問題是指某個鍵的值占用了過多…

【STM32開發板】接口部分

一、USB接口 可以看到USBP和USBN與PA12,PA11引腳相接,根據協議&#xff0c;需要添加上拉電阻 二、ADC和DAC 根據原理圖找到可以作為ADC和DAC的引腳 ADC和DAC屬于模擬部分的&#xff0c;所以要接模擬地 三、指示燈電路 找幾個通用的引腳&#xff0c;因為單片機的灌電流比拉電流…

[Hackers and Painters] 讀書筆記 | 設計模式思想 | LISP

目錄 黑客與藝術的關系 “如果你有兩個選擇&#xff0c;就選擇較難的那個“ 金錢不等于財富。創造有價值的東西就是創造財富 項目公式 探討關于優秀程序員的話題 摘抄 保羅格雷厄姆其人其事 人物經歷 圖書介紹 個人作品編輯 譯者序 為什么書呆子不受歡迎 黑客與畫…

Linux基本指令/下

目錄 1.echo、cat與printf 2. > 操作符 與 >> 操作符 3. < 操作符 4.消息傳送 linux文件深入 5.文件類型 6.mv命令 7.時間相關指令 8.查找命令 9.grep命令 10.zip/unzip/tar命令 11.scp命令 12.bc命令 13.uname 指令 14.快捷鍵大全 15.關機/重啟/睡…

Apptrace:APP安全加速解決方案

2021 年&#xff0c;某知名電商平臺在 “618” 大促期間遭遇 DDoS 攻擊&#xff0c;支付系統癱瘓近 2 小時&#xff1b;2022 年&#xff0c;一款熱門手游在新版本上線時因 CC 攻擊導致服務器崩潰。觀察發現&#xff0c;電商大促、暑期流量高峰和年末結算期等關鍵商業周期&#…

NodeJS全棧開發面試題講解——P1Node.js 基礎與核心機制

? 1.1 Node.js 的事件循環原理&#xff1f;如何處理異步操作&#xff1f; 面試官您好&#xff0c;我理解事件循環是 Node.js 的異步非阻塞編程核心。 Node.js 構建在 V8 引擎與 libuv 庫之上。雖然 Node.js 是單線程模型&#xff0c;但它通過事件循環&#xff08;event loop&a…

【深度學習】sglang 的部署參數詳解

SGLang 的部署參數詳解 SGLang(Structured Generation Language)是一個高性能的大語言模型推理框架,專為結構化生成和多模態應用設計。本文將全面介紹SGLang的部署參數,幫助你充分發揮其性能潛力。 ?? SGLang 項目概覽 SGLang是由UC Berkeley開發的新一代LLM推理引擎,…

MATLAB實戰:機器學習分類回歸示例

以下是一個使用MATLAB的Statistics and Machine Learning Toolbox實現分類和回歸任務的完整示例代碼。代碼包含鳶尾花分類、手寫數字分類和汽車數據回歸任務&#xff0c;并評估模型性能。 %% 加載內置數據集 % 鳶尾花數據集&#xff08;分類&#xff09; load fisheriris; X_i…

數組。。。。。

//創建Book 對象&#xff0c;放入相關的屬性private String name;//書名private String[] writer;//作者private List<String> reader;//讀者private Map<String, Object> topics;//評講Book book new Book();book.setName("昆蟲總動員");book.setWrite…

day16 leetcode-hot100-31(鏈表10)

25. K 個一組翻轉鏈表 - 力扣&#xff08;LeetCode&#xff09; 1.模擬法 思路 將這個過程拆解為兩個步驟&#xff0c;第一步將單分組的節點反轉&#xff0c;第二步將反轉后的鏈表加入原鏈表。 針對節點反轉很容易&#xff0c;參考之前的206. 反轉鏈表 - 力扣&#xff08;Le…

測試總結(二)

持續集成 軟件開發實踐 開發提交代碼到gitlab上 自動化構建&#xff08;編譯、打包、部署、自動化測試&#xff09; 盡早發現集成問題 過程&#xff1a; 提交代碼-人工/定時觸發-自動構建-自動部署-構建成功-獲取構建環境信息-郵件通知-自動測試 快速集成、快速反饋、快速解決…

(二)微服務(grpc/grpc消費者)

文章目錄 項目地址一、grpc介紹1.1 項目初始化1. 創建grpc項目2. 項目結構二、Discount grpc創建2.1 實體層1. Coupon實體2.2 Protos1. 創建discount.proto2. 配置proto3. 創建DiscountService4. Program里注冊服務2.3 Seed 數據1. 創建表和Seed數據2. 自動migration2.4 更新Do…

InfluxQL 數據分析實戰:聚合、過濾與關聯查詢全解析

InfluxQL 作為時序數據庫的專用查詢語言&#xff0c;在處理時間序列數據時展現出獨特優勢。本文深入探討 聚合計算、數據過濾和跨測量關聯 三大核心操作&#xff0c;通過真實代碼示例展示如何從海量時序數據中提取關鍵洞察。文中涵蓋從基礎平均值計算到復雜多維度分析的完整流程…

TDengine 運維——巡檢工具(安裝前檢查)

簡介 本文檔旨在介紹 TDengine 安裝部署前后配套的巡檢工具。 相關工具的功能簡介&#xff1a; 工具名稱功能簡介安裝前檢查部署前對 TDengine 安裝部署的依賴要素進行安裝前檢查安裝前預配置部署前對 TDengine 安裝部署的依賴要素進行安裝前預配置安裝部署指定環境安裝部署…

大語言模型(LLM)入門 - (1) 相關概念

文章來自&#xff1a;大語言模型(LLM)小白入門自學項目-TiaoYu-1 GitHub - tiaoyu1122/TiaoYu-1: For People! For Freedom!For People! For Freedom! Contribute to tiaoyu1122/TiaoYu-1 development by creating an account on GitHub.https://github.com/tiaoyu1122/TiaoYu…

LearnOpenGL-筆記-其十一

Normal Mapping 又到了介紹法線貼圖的地方&#xff0c;我感覺我已經寫了很多遍了... 法線貼圖用最簡單的話來介紹的話&#xff0c;就是通過修改貼圖對應物體表面的法線來修改光照效果&#xff0c;從而在不修改物體實際幾何形狀的前提下實現不同于物體幾何形狀的視覺效果。 因…

Spring Boot 讀取.env文件獲取配置

Spring Boot 讀取.env文件獲取配置 在Resouce 目錄下創建.env文件 # DEEP SEEK TOKEN DEEP_SEEK_TOKENyour_deep_seek_key # 阿里云百煉 TOKEN ALI_BAILIAN_TOKENyour_ali_bailian_keyyml引入.env文件 spring:config:import: optional:classpath:.env[.properties]使用.env文…

【C++高級主題】命令空間(三):未命名的命名空間

目錄 一、未命名的命名空間的基本概念 1.1 定義與特點 1.2 基本語法 1.3 訪問方式 1.4 未命名的命名空間的作用 二、未命名的命名空間與靜態聲明的比較 2.1 靜態聲明的作用 2.2 未命名的命名空間的優勢 2.3 示例代碼比較 2.4. 未命名的命名空間的作用域和鏈接屬性 三…

【Unity】AudioSource超過MaxDistance還是能聽見

unity版本&#xff1a;2022.3.51f1c1 將SpatialBlend拉到1即可 或者這里改到0 Hearing audio outside max distance - #11 by wderstine - Questions & Answers - Unity Discussions

多個vue2工程共享node_modules

手頭有多個vue2項目&#xff0c;它們每個都需要一個node_modules&#xff0c;拷貝起來超級麻煩。于是想到能否共享一個node_modules呢&#xff1f;&#xff1f; 方法其實挺多&#xff0c;我選擇了一個較簡單的&#xff1a;符號連接法(win11平臺) 創建方法很簡單&#xff1a;比…