設計模式——狀態設計模式(行為型)

摘要

狀態設計模式是一種行為型設計模式,核心在于允許對象在內部狀態改變時改變行為。它通過狀態對象封裝不同行為,使狀態切換靈活清晰。該模式包含環境類、抽象狀態類和具體狀態類等角色,具有避免大量分支判斷、符合單一職責和開閉原則等特點。適用于訂單狀態管理、流程審批等場景,其結構清晰,實現方式多樣,能有效解決狀態切換問題。

1. 狀態設計模式定義

狀態設計模式(State Pattern)是一種行為型設計模式,它的核心思想是:允許對象在其內部狀態改變時改變它的行為,使得看起來就像修改了它的類。狀態模式允許一個對象在其內部狀態發生改變時改變它的行為。這個對象看起來就像修改了它的類一樣。

狀態模式就像一個“帶有狀態的自動售貨機”——投幣、選擇商品、出貨,每個動作在不同狀態下有不同結果。我們通過狀態對象來封裝不同的行為,讓狀態切換變得靈活而清晰。

1.1. 🧩 角色組成:

角色

說明

Context

環境類,持有當前狀態,定義對外接口,委托狀態對象處理行為

State

抽象狀態接口,定義所有狀態的行為方法

ConcreteState

具體狀態類,實現不同狀態下的行為邏輯,并負責狀態切換

1.2. ? 特點

  • 避免了大量 if-elseswitch-case 分支判斷
  • 每個狀態封裝一個獨立的行為邏輯,符合單一職責原則
  • 狀態切換內聚在狀態對象內部,符合“開閉原則”

1.3. 🧾 示例場景

  • 訂單狀態管理(待支付、已支付、已發貨、已完成)
  • 流程審批引擎(待審核、審核中、已駁回、已通過)
  • 自動售貨機、工作流、任務調度狀態機等

2. 狀態設計模式結構

狀態模式包含如下角色:

  • Context: 環境類
  • State: 抽象狀態類
  • ConcreteState: 具體狀態類

2.1. 狀態設計模式類圖

2.2. 狀態設計模式時序圖

3. 狀態設計模式實現方式

狀態設計模式的實現方式主要依賴對象狀態的封裝狀態間的轉換控制。以下是標準實現方式及其在 Java(或類似面向對象語言)中的常見實現結構。

3.1. 定義抽象狀態接口(State

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

3.2. 定義具體狀態類(ConcreteStateA, ConcreteStateB

public class ConcreteStateA implements State {@Overridepublic void handle(Context context) {System.out.println("當前狀態:A,處理邏輯中...切換到狀態B");context.setState(new ConcreteStateB());}
}public class ConcreteStateB implements State {@Overridepublic void handle(Context context) {System.out.println("當前狀態:B,處理邏輯中...切換到狀態A");context.setState(new ConcreteStateA());}
}

3.3. 定義上下文(環境類 Context

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); // 委托當前狀態處理}
}

3.4. 客戶端調用示例

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

3.5. 狀態設計模式在Spring 或企業項目中的實現方式拓展

在實際項目中,狀態模式常結合如下技術使用:

技術棧/機制

實現方式說明

Spring 容器管理狀態類

使用注解 @Component注入各個狀態類,用 Map<String, State>自動管理所有狀態實現

狀態與事件觸發分離

可結合策略模式或狀態機框架(如 Spring Statemachine)來支持更復雜的狀態轉移圖

結合枚舉做狀態標識

使用枚舉表示狀態常量,再映射到狀態實現類,便于狀態持久化與切換

結合數據庫存儲狀態值

在業務實體中存儲當前狀態字段,狀態類根據字段值決定是否允許轉移

3.6. Java 項目中使用狀態模式的一些變體實現方式

實現方式

說明

經典接口實現

每個狀態一個類,符合設計原則,但類多

枚舉實現狀態

enum 實現 State 接口,每個枚舉項表示一個狀態,簡化類數量

策略+狀態融合

每個狀態類封裝為一個策略行為,通過上下文統一調度

注解驅動(配合 AOP)

某些行為切換狀態可用注解標注事件,然后由切面完成狀態更新

總結:狀態模式通過將“行為”委托給“狀態類”,并在狀態類內部控制狀態轉移,既解耦了狀態判斷邏輯,也增強了可擴展性和靈活性。

4. 狀態設計模式適合場景

4.1. ? 適合使用狀態模式的場景

場景

說明

對象狀態經常變化

如訂單、任務、審批流等有多個明確狀態,且狀態切換頻繁、規則復雜。

狀態行為復雜且相互不同

各狀態對應的行為差異大,不適合用 if/else 處理。例如支付狀態下不能發貨,發貨狀態下不能退款。

狀態切換有明確流程或圖譜

如狀態轉移圖能清晰表示狀態之間的合法路徑,適合模型驅動開發。

希望將狀態行為局部化

避免大量 if-else/switch,在每個狀態類中封裝對應邏輯,提高代碼清晰度。

可擴展性要求高

新增狀態時只需添加一個類,符合開閉原則,不需改動原有邏輯。

工作流引擎/狀態機系統開發

狀態流轉是核心功能,狀態模式天然適配這類系統。

4.2. ? 不適合使用狀態模式的場景

場景

原因

狀態數量很少,邏輯簡單

如只有 2-3 個狀態、行為簡單,使用狀態類反而增加復雜度。

狀態行為一致,僅數據不同

行為一致可以用策略模式或配置表來處理,無需狀態類區分。

狀態轉移規則頻繁變化或不穩定

狀態圖不穩定會導致大量狀態類頻繁調整,維護成本高。

只需要一個條件判斷即可處理的邏輯

強行拆成多個狀態類會讓代碼變啰嗦、不易維護。

資源受限的場景(嵌入式、移動端)

每個狀態一個類可能會增加內存開銷,不如用狀態碼枚舉和 switch 實現更輕量。

4.3. 🧠 總結:

如果你面對的是有限狀態機問題(FSM),狀態之間行為差異大且需頻繁切換,那狀態設計模式就是非常合適的選擇;反之,則應避免“為了模式而模式”。

5. 狀態設計模式實戰示例

5.1. ? 場景說明:

模擬一個信貸風控審批流程,審批任務的狀態有以下幾種:

  • 待初審初審通過復審通過審批完成
  • 各個狀態下行為不同,如“提交”、“退回”、“終止”等

5.2. ? 類結構圖(State 模式組成)

[State]            ← 抽象接口↑   ↑   ↑
[AState] [BState] [CState]  ← 具體狀態類[ApprovalContext] ← 上下文類,包含狀態對象 + 狀態切換邏輯

5.3. 🛠 抽象狀態接口

public interface ApprovalState {void submit(ApprovalContext context);void reject(ApprovalContext context);String getStateCode(); // 標識狀態
}

5.4. 🛠 上下文類(使用 Spring 注解注入狀態對象)

@Component
public class ApprovalContext {// 所有狀態實現類注入到 Map,key 為狀態 code@Autowiredprivate List<ApprovalState> stateList;private Map<String, ApprovalState> stateMap;private ApprovalState currentState;@PostConstructpublic void init() {stateMap = stateList.stream().collect(Collectors.toMap(ApprovalState::getStateCode, s -> s));}public void setCurrentState(String stateCode) {this.currentState = stateMap.get(stateCode);}public void submit() {currentState.submit(this);}public void reject() {currentState.reject(this);}public String getCurrentStateCode() {return currentState.getStateCode();}
}

5.5. 🛠 具體狀態實現類(以“待初審”為例)

@Component
public class WaitInitialApprovalState implements ApprovalState {@Overridepublic void submit(ApprovalContext context) {System.out.println("當前狀態:待初審 → 執行提交 → 切換到初審通過");context.setCurrentState("APPROVED_INIT");}@Overridepublic void reject(ApprovalContext context) {System.out.println("當前狀態:待初審 → 執行駁回 → 切換到終止狀態");context.setCurrentState("TERMINATED");}@Overridepublic String getStateCode() {return "WAIT_INIT";}
}

再如 “初審通過” 狀態:

@Component
public class ApprovedInitialState implements ApprovalState {@Overridepublic void submit(ApprovalContext context) {System.out.println("當前狀態:初審通過 → 執行提交 → 切換到復審通過");context.setCurrentState("APPROVED_FINAL");}@Overridepublic void reject(ApprovalContext context) {System.out.println("當前狀態:初審通過 → 駁回 → 回到初審");context.setCurrentState("WAIT_INIT");}@Overridepublic String getStateCode() {return "APPROVED_INIT";}
}

5.6. 🧪 控制層模擬調用

@RestController
@RequestMapping("/approval")
public class ApprovalController {@Autowiredprivate ApprovalContext context;@GetMapping("/start")public String start() {context.setCurrentState("WAIT_INIT");return "流程已啟動,當前狀態:" + context.getCurrentStateCode();}@PostMapping("/submit")public String submit() {context.submit();return "提交后,當前狀態:" + context.getCurrentStateCode();}@PostMapping("/reject")public String reject() {context.reject();return "駁回后,當前狀態:" + context.getCurrentStateCode();}
}

5.7. 🧠 技術亮點

說明

? Spring 注解注入

使用 @Component + @Autowired 注解將所有狀態自動注冊并注入上下文

? Map 管理狀態

使用 @PostConstruct 構建狀態映射,方便通過 stateCode 切換狀態

? 避免構造注入

通過字段注入 List<ApprovalState>,不依賴構造函數

? 易于擴展

添加新狀態只需新增一個實現類,無需修改原有邏輯,符合開閉原則

5.8. ? 總結:

本示例將狀態設計模式與 Spring 注解機制結合,實現了一個靈活、可擴展的金融風控審批流程狀態機,適合真實風控系統中審批流、處理流的狀態管理需求。

6. 狀態設計模式思考

6.1. 狀態設計模式與狀態機設計有什么關系?

狀態設計模式(State Pattern)與狀態機(State Machine)有密切關系,但兩者側重點不同。理解它們的聯系與區別有助于你在項目中正確選擇使用方式,特別是在風控、審批流等系統中。

6.1.1. ? 二者關系概述:

項目

狀態設計模式(State Pattern)

狀態機(State Machine)

核心概念

將狀態行為封裝為類,行為由當前狀態對象決定

明確的狀態集合、事件集合、轉移規則

關注點

封裝狀態行為和狀態切換邏輯(面向對象)

管理狀態 + 事件 + 轉移圖譜(面向模型)

表達能力

表達某對象在不同狀態下行為不同

能描述復雜的狀態流、事件觸發與狀態轉移

實現方式

使用狀態類、上下文對象,代碼驅動

可以是代碼、配置、狀態轉移圖、框架等

適合場景

狀態數有限,行為差異大,關注行為封裝

狀態眾多,轉移復雜,關注狀態流和路徑

是否一定使用類

? 每個狀態類實現接口

? 可純配置(如狀態轉移表、DSL)

常見代表

狀態模式(GoF)

有限狀態機(FSM)、Spring Statemachine

6.1.2. ? 類比舉例:審批流程

  • 狀態設計模式
    你創建 WaitApprovalStateApprovedStateRejectedState 等類,在類中定義“提交”、“駁回”等行為。
  • 狀態機模型
    你建一個狀態圖:
    WAIT_APPROVAL --(submit)--> APPROVED
    WAIT_APPROVAL --(reject)--> REJECTED
    并用框架(如 Spring Statemachine)實現。

6.1.3. ? 狀態設計模式 vs 狀態機的總結圖解:

                    ┌─────────────────────┐│   狀態設計模式       ││  封裝狀態行為         ││  各狀態一個類         │└────────┬────────────┘│▼狀態邏輯復雜,可擴展性強│▼┌─────────────────────┐│    狀態機模型        ││  管理狀態轉移路徑     ││  可視化或配置驅動     │└─────────────────────┘

6.2. ? 實踐建議

情況

推薦方案

狀態較少、行為差異大

使用狀態設計模式,可讀性強、便于擴展

狀態較多、轉移復雜、事件驅動

使用狀態機模型(框架),如 Spring Statemachine

想表達清晰狀態流

先畫出狀態圖,用狀態機模型來支撐業務流程設計

6.3. 🧠 總結:

狀態設計模式是狀態機的一種實現方式,適用于行為封裝;而狀態機更偏向建模工具,適用于流程表達和自動化管理。兩者可以結合使用,如狀態類 + 狀態圖配置來實現靈活狀態系統。

博文參考

  • 4. 狀態模式 — Graphic Design Patterns
  • 狀態設計模式
  • 設計模式之狀態模式 | DESIGN

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

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

相關文章

C++ 觀察者模式:設計與實現詳解

一、引言 在現代軟件開發中,組件間的交互與通信是系統設計的核心挑戰之一。觀察者模式(Observer Pattern)作為一種行為設計模式,提供了一種優雅的解決方案,用于實現對象間的一對多依賴關系。本文將深入探討 C++ 中觀察者模式的設計理念、實現方式及其應用場景。 二、觀察…

Windows 賬號管理與安全指南

Windows 賬號管理與安全指南 概述 Windows 賬號管理是系統安全的基礎&#xff0c;了解如何正確創建、管理和保護用戶賬戶對于系統管理員和安全專業人員至關重要。本文詳細介紹 Windows 系統中的賬戶管理命令、隱藏賬戶創建方法以及安全防護措施。 基礎賬戶管理命令 net use…

[藍橋杯]擺動序列

擺動序列 題目描述 如果一個序列的奇數項都比前一項大&#xff0c;偶數項都比前一項小&#xff0c;則稱為一個擺動序列。即 a2i<a2i?1,a2i1 >a2ia2i?<a2i?1?,a2i1? >a2i?。 小明想知道&#xff0c;長度為 mm&#xff0c;每個數都是 1 到 nn 之間的正整數的…

Python 網絡編程 -- WebSocket編程

作者主要是為了用python構建實時網絡通信程序。 概念性的東西越簡單越好理解,因此,下面我從晚上摘抄的概念 我的理解。 什么是網絡通信? 更確切地說&#xff0c;網絡通信是兩臺計算機上的兩個進程之間的通信。比如&#xff0c;瀏覽器進程和新浪服務器上的某個Web服務進程在通…

GM DC Monitor如何實現TCP端口狀態監控-操作分享

本節講解如何通過現有指標提取監控腳本制作自定義的TCP端口監控指標 一、功能介紹 通過提取已有的監控指標的監控命令&#xff0c;來自定義TCP端口的監控指標。 二、配置端口監控 1&#xff09;定位監控腳本 確定腳本及參數如下&#xff1a; check_protocol_tcp.pl --plug…

LabVIEW與Modbus/TCP溫濕度監控系統

基于LabVIEW 開發平臺與 Modbus/TCP 通信協議&#xff0c;設計一套適用于實驗室環境的溫濕度數據采集監控系統。通過上位機與高精度溫濕度采集設備的遠程通信&#xff0c;實現多設備溫濕度數據的實時采集、存儲、分析及報警功能&#xff0c;解決傳統人工采集效率低、環境適應性…

Ntfs!ReadIndexBuffer函數分析之nt!CcGetVirtualAddress函數之nt!CcGetVacbMiss

第一部分&#xff1a; NtfsMapStream( IrpContext, Scb, LlBytesFromIndexBlocks( IndexBlock, Scb->ScbType.Index.IndexBlockByteShift ), Scb->ScbType.Index.BytesPerIndexBuffer, &am…

vite+vue3項目中,單個組件中使用 @use報錯

報錯信息&#xff1a; [plugin:vite:css] [sass] use rules must be written before any other rules.use 官方說明 注意事項&#xff1a; https://sass-lang.com/documentation/at-rules/use/ 樣式表中的 use 規則必須位于所有其他規則&#xff08;除 forward 外&#xff0…

基于VMD-LSTM融合方法的F10.7指數預報

F10.7 Daily Forecast Using LSTM Combined With VMD Method ??F10.7?? solar radiation flux is a well-known parameter that is closely linked to ??solar activity??, serving as a key index for measuring the level of solar activity. In this study, the ??…

React 新項目

使用git bash 創建一個新項目 建議一開始就創建TS項目 原因在Webpack中改配置麻煩 編譯方法:ts compiler 另一種 bable 最好都配置 $ create-react-app cloundmusic --template typescript 早期react項目 yarn 居多 目前npm包管理居多 目前pnpm不通用 icon 在public文件夾中…

2025年- H65-Lc173--347.前k個高頻元素(小根堆,堆頂元素是當前堆元素里面最小的)--Java版

1.題目描述 2.思路 &#xff08;1&#xff09;這里定義了一個小根堆&#xff08;最小堆&#xff09;&#xff0c;根據元素的頻率從小到大排序。小根堆原理&#xff1a;堆頂是最小值&#xff0c;每次插入或刪除操作會保持堆的有序結構&#xff08;常用二叉堆實現&#xff09;。 …

VR/AR 顯示瓶頸將破!鐵電液晶技術迎來關鍵突破

在 VR/AR 設備逐漸走進大眾生活的今天&#xff0c;顯示效果卻始終是制約其發展的一大痛點。紗窗效應、畫面拖影、眩暈感…… 傳統液晶技術的瓶頸讓用戶體驗大打折扣。不過&#xff0c;隨著鐵電液晶技術的重大突破&#xff0c;這一局面有望得到徹底改變。 一、傳統液晶技術瓶頸…

【bug】Error: /undefinedfilename in (/tmp/ocrmypdf.io.9xfn1e3b/origin.pdf)

在使用ocrmypdf的時候&#xff0c;需要Ghostscript9.55及以上的版本&#xff0c;但是ubuntu自帶為9.50 然后使用ocrmypdf報錯了 sudo apt update sudo apt install ghostscript gs --version 9.50 #版本不夠安裝的版本為9.50不夠&#xff0c;因此去官網https://ghostscript.c…

【TinyWebServer】線程同步封裝

目錄 POSIX信號量 int sem_init(sem_t* sem,int pshared,unsingned int value); int sem_destroy(sem_t* sem); int sem_wait(sem_t* sem); int sem_post(sem_t* sem); 互斥量 條件變量 為了對多線程程序實現同步問題&#xff0c;可以用信號量POSIX信號量、互斥量、條件變…

打造高效多模態RAG系統:原理與評測方法詳解

引言 隨著信息檢索與生成式AI的深度融合&#xff0c;檢索增強生成&#xff08;RAG, Retrieval-Augmented Generation&#xff09; 已成為AI領域的重要技術方向。傳統RAG系統主要依賴文本數據&#xff0c;但真實世界中的信息往往包含圖像、表格等多模態內容。多模態RAG&#xf…

Unity安卓平臺開發,啟動app并傳參

using UnityEngine; using System;public class IntentReceiver : MonoBehaviour {public bool isVR1;void Start(){Debug.LogError("app1111111111111111111111111");if (isVR1){LaunchAnotherApp("com.HappyMaster.DaKongJianVR2");}else{// 檢查是否有傳…

云計算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】

云計算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】 目錄 云計算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】1.RPM包的一般安裝位置2.軟件名和軟件包名3.查詢軟件信息4.查詢軟件包5.導入紅帽簽名信息&#xff0c;解決查詢軟件包信息報錯6.利用…

【圖像處理3D】:點云圖是怎么生成的

點云圖是怎么生成的 **一、點云數據的采集方式****1. 激光雷達&#xff08;LiDAR&#xff09;****2. 結構光&#xff08;Structured Light&#xff09;****3. 雙目視覺&#xff08;Stereo Vision&#xff09;****4. 飛行時間相機&#xff08;ToF Camera&#xff09;****5. 其他…

javaweb -html -CSS

HTML是一種超文本標記語言 超文本&#xff1a;超過了文本的限制&#xff0c;比普通文本更強大&#xff0c;除了文字信息&#xff0c;還可以定義圖片、音頻、視頻等內容。 標記語言&#xff1a;由標簽"<標簽名>"構成的語言。 CSS:層疊樣式表&#xff0c;用于…

pyinstaller 安裝 ubuntu

安裝命令 pip install pyinstaller 讀取安裝路徑 ? ~ find ~/.local/ -name pyinstaller/home/XXX/.local/bin/pyinstaller 路徑配置 vi ~/.zshrc 添加到文件最后 export PATH"$PATH:/home/XXX/.local/bin/" 查看版本號 ? ~ source ~/.zshrc? ~ pyi…