狀態模式 (State Pattern)

定義

狀態模式(State Pattern)是一種行為型設計模式,它允許一個對象在其內部狀態改變時改變它的行為。這種模式將每個狀態的行為封裝到對應的狀態類中,使得上下文(Context)的行為隨著其內部狀態的改變而改變,看起來像是改變了其類。

結構

狀態模式通常包含以下角色:

  • 上下文(Context):維護一個指向當前狀態對象的引用,并將與狀態相關的行為委托給當前狀態對象。
  • 狀態(State):定義一個接口,封裝與上下文的一個特定狀態相關的行為。
  • 具體狀態(Concrete States):實現狀態接口的類,每一個類封裝了上下文對象的一個特定狀態的行為。
解決的問題
  • 行為隨狀態改變
    • 當一個對象的行為依賴于其內部狀態,并且需要在運行時根據狀態的改變而改變行為時,狀態模式提供了一種清晰的方式來實現這種依賴。
  • 狀態邏輯分散問題
    • 在沒有使用狀態模式的情況下,對象的狀態邏輯常常分散在整個對象中,尤其是在對象的行為受多個狀態影響時。狀態模式通過將每個狀態的行為封裝在單獨的類中,使得狀態相關的邏輯集中管理。
  • 復雜的條件選擇結構
    • 狀態模式幫助避免在對象的行為實現中使用復雜的條件選擇結構(如if-else或switch-case語句)。通過將行為封裝在狀態對象中,可以使用多態替代條件語句。
  • 狀態轉換的顯式表示
    • 狀態模式使得狀態的轉換過程更加明確和顯式。狀態對象可以控制轉換到下一個狀態的邏輯,這樣狀態轉換規則就不再隱含在對象的行為實現中。
  • 狀態增加的靈活性
    • 使用狀態模式時,新增狀態只涉及添加一個新的狀態類。這比在原有的條件邏輯中添加新的分支要清晰和簡單得多,同時也更容易維護。
使用場景
  • 對象的行為取決于其狀態
    • 當一個對象的行為隨其內部狀態的改變而改變時,狀態模式是非常適用的。例如,一個文檔可能有多種狀態(如草稿、審閱、發布),每種狀態下的行為(如編輯、審批、發布)都不同。
  • 復雜的條件分支控制
    • 當一個操作包含大量的條件分支,并且這些分支依賴于對象的狀態時,使用狀態模式可以避免復雜的條件分支邏輯,使得代碼更易于理解和維護。
  • 狀態的轉換邏輯顯式化
    • 如果狀態轉換的邏輯很復雜,或者有多個地方會觸發狀態轉換,狀態模式可以使這些邏輯集中管理,避免分散在系統的各個部分,從而降低出錯的概率。
  • 狀態機的實現
    • 對于那些可以用狀態機來描述的系統,狀態模式提供了一種清晰的實現方式。每個狀態都是狀態機的一個節點,狀態轉換則對應于狀態機的邊。
  • 減少代碼重復
    • 如果在不同狀態下的行為有重復代碼,狀態模式可以幫助組織和重用這些代碼,尤其是當這些行為在狀態間有細微差別時。
示例代碼1-交通信號燈
// 狀態接口
interface TrafficLightState {void change(TrafficLight trafficLight);
}// 具體狀態:紅燈
class RedLight implements TrafficLightState {public void change(TrafficLight trafficLight) {System.out.println("Red Light - Stop");trafficLight.setState(new GreenLight());}
}// 具體狀態:綠燈
class GreenLight implements TrafficLightState {public void change(TrafficLight trafficLight) {System.out.println("Green Light - Go");trafficLight.setState(new YellowLight());}
}// 具體狀態:黃燈
class YellowLight implements TrafficLightState {public void change(TrafficLight trafficLight) {System.out.println("Yellow Light - Caution");trafficLight.setState(new RedLight());}
}// 上下文
class TrafficLight {private TrafficLightState state;public TrafficLight(TrafficLightState state) {this.state = state;}public void setState(TrafficLightState state) {this.state = state;}public void change() {state.change(this);}
}// 客戶端代碼
public class TrafficLightDemo {public static void main(String[] args) {TrafficLight trafficLight = new TrafficLight(new RedLight());trafficLight.change(); // Red Light - StoptrafficLight.change(); // Green Light - GotrafficLight.change(); // Yellow Light - Caution}
}
示例代碼2-文檔狀態管理
// 狀態接口
interface DocumentState {void next(Document doc);void prev(Document doc);void printStatus();
}// 具體狀態:草稿
class Draft implements DocumentState {public void next(Document doc) {doc.setState(new Review());}public void prev(Document doc) {System.out.println("The document is in its initial state.");}public void printStatus() {System.out.println("Document in Draft state.");}
}// 具體狀態:審閱
class Review implements DocumentState {public void next(Document doc) {doc.setState(new Published());}public void prev(Document doc) {doc.setState(new Draft());}public void printStatus() {System.out.println("Document in Review state.");}
}// 具體狀態:發布
class Published implements DocumentState {public void next(Document doc) {System.out.println("The document is already published.");}public void prev(Document doc) {doc.setState(new Review());}public void printStatus() {System.out.println("Document in Published state.");}
}// 上下文
class Document {private DocumentState state;public Document() {state = new Draft();}public void setState(DocumentState state) {this.state = state;}public void next() {state.next(this);}public void prev() {state.prev(this);}public void printStatus() {state.printStatus();}
}// 客戶端代碼
public class DocumentDemo {public static void main(String[] args) {Document document = new Document();document.printStatus(); // Document in Draft state.document.next();document.printStatus(); // Document in Review state.document.next();document.printStatus(); // Document in Published state.}
}
主要符合的設計原則
  • 開閉原則(Open-Closed Principle)
    • 狀態模式允許在不修改現有代碼的情況下添加新狀態。這是因為你可以添加新的狀態類來擴展系統的行為,而無需更改現有的上下文或其他狀態類。因此,系統對于擴展是開放的,但對于修改是封閉的。
  • 單一職責原則(Single Responsibility Principle)
    • 在狀態模式中,每個狀態類僅負責管理與其狀態相關的行為,而上下文類則負責維護狀態和委托狀態相關的任務。這樣,每個類只有一個改變的原因,即它所代表的狀態的行為,從而符合單一職責原則。
  • 里氏替換原則(Liskov Substitution Principle)
    • 狀態模式中的每個具體狀態都是通過狀態接口或抽象狀態類實現的,這意味著它們都可以互換使用。因此,任何時候都可以使用這些具體狀態來替代狀態接口,這符合里氏替換原則。
在JDK中的應用
  • java.util.Iterator
    • Iterator 接口的實現類通常會根據內部的集合狀態(如集合的當前位置)來改變其行為。例如,在遍歷過程中,hasNext()next() 方法的行為取決于迭代器的當前位置。
  • java.net.URLConnection
    • URLConnection 類及其子類有不同的狀態,如連接前和連接后。在連接打開之后,嘗試修改連接屬性(如調用 setDoOutput() 方法)將拋出異常,表明其行為隨狀態變化。
  • java.nio.channels.Selector
    • 在Java NIO中,Selector 類的行為依賴于它當前的狀態(如打開或關閉狀態)。選擇器的某些操作只在打開狀態下有效,而在關閉狀態下會有不同的行為或拋出異常。
在Spring中的應用
  • Spring Web Flow
    • Spring Web Flow是Spring框架的一個擴展,它管理著基于狀態的流程。在這種情況下,根據當前流程的狀態(如步驟或頁面),應用程序的行為會有所不同。Spring Web Flow通過定義狀態和轉換來管理復雜的流程邏輯。
  • Spring狀態機(Spring State Machine)
    • Spring State Machine提供了一種系統化的方式來實現狀態模式,允許定義狀態、事件和在不同狀態下觸發的行為。雖然這是一個獨立的項目,但它與Spring框架集成,為實現基于狀態的邏輯提供了更結構化的方法。
  • Spring Security的認證流程
    • 在Spring Security中,認證和授權流程可能根據不同的狀態(如已認證、未認證、授權失敗)執行不同的邏輯。例如,不同的認證提供者可以根據上下文或安全令牌的狀態來決定認證邏輯。
  • Spring Session
    • 在Spring Session中,會話的狀態(如新建、已存在、過期)可以決定某些行為(如會話創建、會話獲取、會話失效)。

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

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

相關文章

公眾號違禁詞及違規行為匯總

1、微信官方發布《微信公眾平臺關于清理集贊行為的公告》,全面禁止公眾賬號“集贊”玩法。 微信對違反微信用戶協議和公眾平臺協議的公眾號處理機制是,公眾號累計發現一次有集贊行為,封號7天;公眾號累計發現二次有集贊行為&#…

面試:ShardingSphere問題

文章目錄 什么是ShardingSphere,它的主要功能是什么?ShardingSphere的核心模塊有哪些?他們是如何工作的?ShardingSphere 的讀寫分離是如何實現的?如何配置ShardingSphere的數據分片策略?ShardingSphere支持…

【運維面試100問】(六)buffer和cache的區別

本站以分享各種運維經驗和運維所需要的技能為主 《python零基礎入門》:python零基礎入門學習 《python運維腳本》: python運維腳本實踐 《shell》:shell學習 《terraform》持續更新中:terraform_Aws學習零基礎入門到最佳實戰 《k8…

【Linux】匿名管道+進程池

文章目錄 前置知識一、管道的原理二、管道的特性三、管道的接口四、使用管道實現簡單的進程池解決進程池的一個小問題 前置知識 一個進程在創建時,會默認打開三個文件,分別是:stdin,stdout,stderr 進程中有一個維護進…

1linux

Is查看目錄內容 ls -ahil a表示全部,h表示文件大小以人類易讀的形式給出,i表示索引節點,l表示長列表形式。 cd 切換目錄 touch 創建文件 mkdir 創建目錄 mkdir Makedirectory,創建目錄,-p指定路徑,-m指定權…

炫我出席數字光影工作室專業建設論壇,受聘為專家委員會委員!

11月18日,炫我科技受邀參加在北京深瀾AI空間舉辦的2023數字光影工作室專業建設論壇。本次活動由北京市新媒體技師學院主辦、北京瀾景科技有限公司協辦,私有云售前技術工程師龔琛代表我司出席,并受聘為新媒體技師學院數字光影工作室專家委員會…

Mysql基礎操作(命令行)

文章目錄 Mysql基礎操作(命令行)背景創建數據庫選擇數據庫查看所有表查看表結構向表插入數據插入第一條插入第二條插入第三條 查詢表數據修改表數據刪除表數據 Mysql基礎操作(命令行) 背景 docker安裝mysql8,映射本地…

ubuntu下,PX4使用 upload 下載代碼沒反應

可能原因,沒有串口權限 sudo chmod 777 /dev/ttyACM0開啟串口權限,本次問題解決。

GTC2023全球流量大會蓄勢待發,菊風在7B57展位等你!

第六屆 GTC 全球流量大會(以下簡稱 GTC2023)將于12月5日- 6日,在深圳福田會展中心7&8號館舉辦。 據悉,本屆大會將是歷屆以來規模最大、參與人數最多、跨境出海資源最豐富的一次行業盛會。7、8 號館共 15000 平方米&am…

計算機組成原理-磁盤存儲器

文章目錄 總覽外存儲器磁盤存儲器磁盤的性能指標磁盤地址磁盤的工作過程磁盤陣列 總結 總覽 外存儲器 磁盤存儲器 寫是利用電流產生磁場從而寫磁盤 讀是利用載磁體移動時產生的電場從而得到數據 磁性材質易受外界磁場干擾 下圖中 載磁體上N S的前后順序代表對應存儲二進制的比…

【深度學習】卷積神經網絡(CNN)的參數優化方法

著名: 本文是從 Michael Nielsen的電子書Neural Network and Deep Learning的深度學習那一章的卷積神經網絡的參數優化方法的一些總結和摘錄,并不是我自己的結論和做實驗所得到的結果。我想Michael的實驗結果更有說服力一些。本書在github上有中文翻譯的…

【不同請求方式在springboot中對應的注解】

GET 請求方法&#xff1a;用于獲取資源。使用 GetMapping 注解來處理 GET 請求。 示例代碼&#xff1a; RestController public class MyController {GetMapping("/resource")public ResponseEntity<String> getResource() {// 處理 GET 請求邏輯} }POST 請求方…

喜訊!云起無垠成為國家信息安全漏洞庫(CNNVD)技術支撐單位

近日&#xff0c;云起無垠憑借其在漏洞挖掘、漏洞檢測以及漏洞修復等領域的卓越表現&#xff0c;榮獲“國家信息安全漏洞庫&#xff08;CNNVD&#xff09;技術支撐單位等級證書&#xff08;三級&#xff09;”&#xff0c;正式成為CNNVD技術支撐單位。 中國國家信息安全漏洞庫&…

MTK聯發科MT6762/MT6763/MT6765安卓核心板參數規格比較

MT6762安卓核心板 MTK6762安卓核心板是一款工業級高性能、可運行 android9.0 操作系統的 4G智能模塊。 CPU&#xff1a;4xCortex-A53 up to 2.0Ghz/4xCortex-A53 up to 1.5GhzGraphics&#xff1a;IMG GE8320 Up to 650MhzProcess&#xff1a;12nmMemory&#xff1a;1xLP3 9…

【正點原子STM32連載】 第六十章 串口IAP實驗(Julia分形)實驗 摘自【正點原子】APM32F407最小系統板使用指南

1&#xff09;實驗平臺&#xff1a;正點原子APM32F407最小系統板 2&#xff09;平臺購買地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套實驗源碼手冊視頻下載地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html## 第六十…

CMake使用file(GLOB ...)需要注意的問題

文章目錄 基本語法使用例子潛在的問題大型項目中推薦的用法 file(GLOB ...) 命令用于獲取匹配指定模式的文件列表。在 CMake 中&#xff0c;file(GLOB ...) 命令的一種常見用法是用于收集源文件列表&#xff0c;例如 C 源文件&#xff08;.cpp&#xff09;和 C 源文件&#xff…

html頁面加載json數據,在html中顯示JSON數據的方法

html頁面加載json數據,在html中顯示JSON數據的方法 export const mixin {methods: {syntaxHighlight(json) {if (typeof json ! string) {json JSON.stringify(json, undefined, 2);}json json.replace(/&/g, &).replace(/</g, <).replace(/>/g, >);re…

實例分割12篇頂會論文及代碼合集,含2023最新

同學們&#xff0c;你們覺得視覺經典四個任務中哪個最難&#xff1f;我個人覺得是實例分割。 因為它既具備語義分割的特點&#xff0c;需要做到像素層面上的分類&#xff0c;也具備目標檢測的一部分特點&#xff0c;即需要定位出不同實例&#xff0c;即使它們是同一種類。 但…

LangChain的函數,工具和代理(一):OpenAI的函數調用

一、什么是函數調用功能 幾個月前OpenAI官方發布了其API的函數調用功能(Function calling), 在 API 調用中&#xff0c;您可以描述函數&#xff0c;并讓模型智能地選擇輸出包含調用一個或多個函數的參數的 JSON 對象。API函數“ChatCompletion” 雖然不會實際調用該函數&#…