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

在軟件開發中,我們經常會遇到對象的行為隨著其內部狀態的變化而變化的情況。例如,一個訂單可能處于"待支付"、"已支付"、"已發貨"或"已完成"等不同狀態,每個狀態下訂單的操作邏輯可能完全不同。如果直接在代碼中使用大量的if-elseswitch-case語句來判斷狀態,會導致代碼臃腫、難以維護,并且違反開閉原則(OCP)

狀態模式(State Pattern)提供了一種優雅的解決方案,它允許對象在運行時根據內部狀態改變其行為,而不必在代碼中顯式地檢查狀態。本文將深入探討狀態模式的核心概念、實現方式、優缺點以及實際應用場景,并通過代碼示例幫助讀者更好地理解該模式。

1. 什么是狀態模式?

1.1 定義

狀態模式是一種行為型設計模式,它允許一個對象在其內部狀態改變時改變其行為,使得對象看起來像是修改了它的類。

1.2 核心思想

  • 將狀態抽象成獨立的類,每個狀態類負責處理該狀態下的行為。

  • 上下文(Context)對象持有一個狀態對象的引用,并將行為委托給當前狀態對象。

  • 狀態轉換由狀態類自身或上下文類控制,而不是在業務邏輯中硬編碼。

1.3 適用場景

  • 對象的行為依賴于它的狀態,并且需要在運行時動態改變行為。

  • 代碼中包含大量與對象狀態相關的條件分支語句,導致邏輯復雜。

  • 狀態轉換邏輯較復雜,且未來可能新增狀態。

2. 狀態模式的結構

狀態模式主要由以下幾個角色組成:

角色作用
Context(上下文)定義客戶端接口,維護當前狀態對象。
State(抽象狀態)定義狀態接口,封裝與特定狀態相關的行為。
ConcreteState(具體狀態)實現狀態接口,處理該狀態下的行為邏輯,并可觸發狀態轉換。

2.1 UML 類圖

┌─────────────┐       ┌─────────────┐
│   Context   │       │    State    │
├─────────────┤       ├─────────────┤
│ -state:State│<>---->│ +handle()   │
├─────────────┤       └─────────────┘
│ +request()  │               ▲
└─────────────┘               ││┌──────────────┴──────────────┐│                             │┌─────────────┐               ┌─────────────┐│ConcreteStateA│               │ConcreteStateB│├─────────────┤               ├─────────────┤│ +handle()   │               │ +handle()   │└─────────────┘               └─────────────┘

3. 代碼示例:訂單狀態管理

假設我們有一個訂單系統,訂單可能處于以下狀態:

  • 待支付(Pending)

  • 已支付(Paid)

  • 已發貨(Shipped)

  • 已完成(Completed)

3.1 定義狀態接口

public interface OrderState {void next(Order order);void prev(Order order);void printStatus();
}

3.2 實現具體狀態類

// 待支付狀態
public class Pending implements OrderState {@Overridepublic void next(Order order) {order.setState(new Paid());}@Overridepublic void prev(Order order) {System.out.println("訂單尚未支付,無法回退。");}@Overridepublic void printStatus() {System.out.println("訂單狀態:待支付");}
}// 已支付狀態
public class Paid implements OrderState {@Overridepublic void next(Order order) {order.setState(new Shipped());}@Overridepublic void prev(Order order) {order.setState(new Pending());}@Overridepublic void printStatus() {System.out.println("訂單狀態:已支付");}
}// 已發貨狀態
public class Shipped implements OrderState {@Overridepublic void next(Order order) {order.setState(new Completed());}@Overridepublic void prev(Order order) {order.setState(new Paid());}@Overridepublic void printStatus() {System.out.println("訂單狀態:已發貨");}
}// 已完成狀態
public class Completed implements OrderState {@Overridepublic void next(Order order) {System.out.println("訂單已完成,無法繼續推進。");}@Overridepublic void prev(Order order) {order.setState(new Shipped());}@Overridepublic void printStatus() {System.out.println("訂單狀態:已完成");}
}

3.3 定義上下文類(Order)

public class Order {private OrderState state;public Order() {this.state = new Pending(); // 初始狀態:待支付}public void setState(OrderState state) {this.state = state;}public void nextState() {state.next(this);}public void prevState() {state.prev(this);}public void printStatus() {state.printStatus();}
}

3.4 客戶端測試

public class Client {public static void main(String[] args) {Order order = new Order();order.printStatus(); // 待支付order.nextState();   // 推進到已支付order.printStatus(); // 已支付order.nextState();   // 推進到已發貨order.printStatus(); // 已發貨order.prevState();   // 回退到已支付order.printStatus(); // 已支付order.nextState();   // 推進到已發貨order.nextState();   // 推進到已完成order.printStatus(); // 已完成}
}

輸出結果:

訂單狀態:待支付
訂單狀態:已支付
訂單狀態:已發貨
訂單狀態:已支付
訂單狀態:已發貨
訂單狀態:已完成

4. 狀態模式的優缺點

4.1 優點

??符合單一職責原則:每個狀態類只負責自己的行為邏輯。
??符合開閉原則(OCP):新增狀態時無需修改現有代碼。
??減少條件分支:避免復雜的if-elseswitch-case邏輯。
??狀態轉換邏輯清晰:狀態轉換由狀態類自身控制,易于維護。

4.2 缺點

??類數量增加:每個狀態都需要一個單獨的類,可能導致類膨脹。
??狀態轉換邏輯分散:如果狀態轉換邏輯復雜,可能難以追蹤。
??可能引入循環依賴:狀態類可能依賴上下文類,反之亦然。

5. 狀態模式的實際應用

5.1 電商訂單系統

  • 訂單狀態流轉:待支付 → 已支付 → 已發貨 → 已完成

  • 不同狀態下,訂單的操作(如取消、退款)邏輯不同。

5.2 游戲角色狀態

  • 角色可能有站立奔跑跳躍攻擊等狀態。

  • 不同狀態下,角色的動畫、移動速度、碰撞檢測等行為不同。

5.3 線程狀態管理

  • Java 線程的狀態:NEWRUNNABLEBLOCKEDWAITINGTERMINATED

  • 不同狀態下,線程的調度策略不同。

5.4 UI 組件狀態

  • 按鈕的狀態:正常懸停按下禁用

  • 不同狀態下,按鈕的樣式和交互邏輯不同。

6. 狀態模式 vs. 策略模式

狀態模式和策略模式在結構上非常相似,但它們的設計意圖不同

對比點狀態模式策略模式
目的讓對象在不同狀態下改變行為讓客戶端選擇不同的算法
狀態轉換狀態類可以自動切換策略通常由客戶端設置
依賴關系狀態類可能依賴上下文策略類通常獨立

7. 總結

狀態模式是一種強大的設計模式,特別適用于對象行為隨狀態變化而變化的場景。它通過將狀態邏輯分散到不同的類中,使得代碼更加清晰、可擴展。盡管它可能增加類的數量,但在復雜狀態管理場景下,它能顯著提升代碼的可維護性。

適用場景總結:

  • 對象有多個狀態,且行為隨狀態變化。

  • 代碼中有大量狀態相關的條件分支。

  • 未來可能新增狀態,需要靈活擴展。

推薦使用場景:
? 訂單狀態管理
? 游戲角色狀態切換
? 線程/進程狀態管理
? UI 組件交互狀態

?

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

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

相關文章

企業級網絡綜合集成實踐:VLAN、Trunk、STP、路由協議(OSPF/RIP)、PPP、服務管理(TELNET/FTP)與安全(ACL)

NE綜合實驗4 一、實驗拓撲二、實驗需求 按照圖示配置IP地址。Sw7和sw8之間的直連鏈路配置鏈路聚合。公司內部業務網段為vlan10和vlan20&#xff0c;vlan10是市場部&#xff0c;vlan20是技術部&#xff0c;要求對vlan進行命名以便區分識別&#xff1b;pc10屬于vlan10&#xff0c…

小架構step系列20:請求和響應的擴展點

1 概述通過上一篇了解請求和響應的流程&#xff0c;Spring在設計上留了不少擴展點。里面通過查找接口的方式獲取的地方&#xff0c;都可以成為一種擴展點&#xff0c;因為只要實現這類接口就可以成為Spring加載的一部分。本文了解一下這些擴展點&#xff0c;方便后面進行擴展。…

模型材質一鍵替換~輕松還原多種三維場景

1. 概述模型的材質決定了三維場景的整體視效&#xff0c;山海鯨可視化不僅支持模型材質的替換與編輯&#xff0c;而且提供了大量現成的模型材質供大家使用&#xff0c;能夠幫助大家實現更高效的三維場景搭建。模型材質主要分為PBR材質和水面材質兩個部分。其中大部分靜態模型都…

【JS逆向基礎】數據庫之mysql

前言&#xff1a;mysql數據庫管理系統&#xff0c;由瑞典MySQL AB 公司開發&#xff0c;目前屬于 Oracle 旗下公司。MySQL 最流行的關MySQL是一個開源免費的關系型數據庫管系型數據庫管理系統&#xff0c;在 WEB 應用方面ySQL是最好的 RDBMS (Relational Database Management S…

金融工程、金融與經濟學知識點

本文整理了20個金融工程、金融和經濟學知識點及邏輯&#xff0c;這些是理解金融市場運作和進行量化分析的基石。 1. 金融工程 - 遠期與期權&#xff08;Forward & Option&#xff09;的定價與風險管理 遠期定價&#xff1a; 利用無套利原則&#xff0c;遠期合約的價格應等…

Vue 3 中導出 Excel 文件

在 Vue 3 中導出 Excel 文件&#xff0c;通常可以使用一些流行的 JavaScript 庫&#xff0c;如 SheetJS (xlsx) 或者 exceljs。這里我將分別介紹如何使用這兩個庫來在 Vue 3 應用中導出 Excel 文件。方法 1&#xff1a;使用 SheetJS (xlsx)安裝 SheetJS首先&#xff0c;你需要安…

奇麟大數據:前端大文件上傳解決方案

在奇麟大數據業務系統的開發及使用過程中&#xff0c;例如OBS對象存儲文件管理、流計算DSC依賴管理&#xff0c;經常會遇到上傳文件這樣的基礎需求&#xff0c;一般情況下&#xff0c;前端上傳文件就是new FormData&#xff0c;然后把文件 append 進去&#xff0c;然后post發送…

立創EDA中雙層PCB疊層分析

立創EDA中雙層PCB疊層分析 結論&#xff1a;立創EDA中的雙層 PCB 疊層視圖相比傳統視圖&#xff0c;多出一個焊盤層&#xff08;博主命名&#xff09;&#xff1b; 1. 傳統雙層 PCB 疊層示意圖 絲印層 印刷元件標識、極性標記及廠商信息 輔助組裝與后期維護 阻焊層 覆蓋銅層表…

深入理解進程:從底層原理到硬件系統實戰

深入理解進程&#xff1a;從底層原理到嵌入式實戰&#xff08;3-4 萬字詳解&#xff09; 前言&#xff1a;為什么硬件開發者必須吃透進程&#xff1f; 作為嵌入式開發者&#xff0c;你可能會說&#xff1a;“我平時用的 RTOS 里只有任務&#xff08;Task&#xff09;&#xff0…

Elasticsearch 簡化指南:GCP Google Compute Engine

作者&#xff1a;來自 Elastic Eduard Martin 系列內容的一部分&#xff1a;開始使用 Elasticsearch&#xff1a;GCP 想獲得 Elastic 認證&#xff1f;看看下一期 Elasticsearch Engineer 培訓什么時候開始&#xff01; Elasticsearch 擁有豐富的新功能&#xff0c;幫助你根據…

STM32的定時器輸入捕獲-超聲波測距案例

STM32的定時器輸入捕獲-超聲波測距案例 gitee代碼輸入捕獲硬件電路案例說明主函數代碼 gitee代碼 https://gitee.com/xiaolixi/l-stm32/tree/master/STM32F103C8T6/2-1tem-ld-timer-input-pluse 輸入捕獲硬件電路 超聲波測距案例說明 使用超聲波測距傳感器使用tim1的輸入捕獲…

[特殊字符] Spring Boot 常用注解全解析:20 個高頻注解 + 使用場景實例

一文掌握 Spring Boot 中最常用的 20 個注解&#xff0c;涵蓋開發、配置、Web、數據庫、測試等場景&#xff0c;配合示例講解&#xff0c;一站式掌握&#xff01;&#x1f4cc; 一、核心配置類注解 1. SpringBootApplication 作用&#xff1a;標記為 Spring Boot 應用的入口類&…

【工具變量】地級市城市包容性綠色增長數據(2011-2023年)

城市包容性綠色增長是指在推動城市經濟增長的過程中&#xff0c;兼顧環境可持續性、社會公平和包容性發展的理念與實踐。它強調在實現綠色轉型和低碳發展的同時&#xff0c;保障社會各群體&#xff0c;特別是弱勢群體的利益與參與權利&#xff0c;確保增長成果能夠公平共享 本…

深入理解React Hooks:從使用到原理

4. 源碼解析類:《深入理解React Hooks:從使用到原理》 # 深入理解React Hooks:從使用到原理?? **背景**: - Hooks解決了Class組件的哪些問題? - 為什么不能在循環/條件中調用Hooks??? **核心原理**:### 1. Hooks鏈表 React內部維護一個單向鏈表:fiber.memoizedSta…

【云原生】Docker 部署 Elasticsearch 9 操作詳解

目錄 一、前言 二、Elasticsearch 9 新特性介紹 2.1 基于 Lucene 10 重大升級 2.2 Better Binary Quantization(BBQ) 2.3 Elastic Distributions of OpenTelemetry(EDOT) 2.4 LLM 可觀測性 2.5 攻擊發現與自動導入 2.6 ES|QL 增強 2.7 語義檢索 三、基于Docker部署…

uview-ui使用u-search搜索框

1、效果圖 2、帶地址搜索框&#xff0c;在微信小程序線上需要開啟地圖定位接口&#xff0c;若沒有權限則顯示不了城市名&#xff0c;注意事項參考uniapp相關地圖 API調用-CSDN博客 <template><view><u-sticky offset-top"-1"><u-search v-mode…

Elasticsearch+Logstash+Kibana部署

目錄 一、實驗準備 1.下載安裝 2.下載java 2.同步主機系統時間 二、部署 1.部署elasticsearch 修改 /etc/elasticsearch/elasticsearch.yml 配置文件 修改 /etc/hosts/ 文件 啟動elasticsearch 查看是否啟動進程netstat -antptu | grep java 2.部署logstash 進入/et…

TEngine學習

關于靜態類中的靜態變量賦值&#xff1a; public static class ActorEventDefine{public static readonly int ScoreChange RuntimeId.ToRuntimeId("ActorEventDefine.ScoreChange");public static readonly int GameOver RuntimeId.ToRuntimeId("ActorEventD…

獵板:在 5G 與 AI 時代,印制線路板如何滿足高性能需求

5G 與 AI 技術的深度融合&#xff0c;推動電子設備向高速傳輸、高算力、高集成方向發展&#xff0c;印制線路板&#xff08;PCB&#xff09;作為核心載體&#xff0c;其性能直接決定終端設備的運行效率與可靠性。獵板 PCB 聚焦 5G 通信的高頻需求與 AI 算力的密集需求&#xff…

教你如何借助AI精讀文獻

目錄1. 原文2. 對文獻有一個快速的理解3. 專業術語解讀4. 解答疑問5. 借助AI翻譯摘要和引言部分5.1 **摘要 (Abstract)**5.2 **引言 (Introduction)**6. 介紹論文中的“Stack-Propagation”7. 查閱論文里的參考文獻&#xff0c;看看他是如何在Introduction中引述研究進展文獻&a…