秒懂设计模式之状态模式(State Pattern)
[版權(quán)申明] 非商業(yè)目的注明出處可自由轉(zhuǎn)載
博文地址:https://blog.csdn.net/ShuSheng0007/article/details/116375477
出自:shusheng007
設(shè)計模式匯總篇,一定要收藏:
永不磨滅的設(shè)計模式(有這一篇真夠了,拒絕標(biāo)題黨)
文章目錄
- 概述
- 類型
- 難度
- 定義
- 使用場景
- UML類圖
- 實例
- 第一,定義一個狀態(tài)接口
- 第二,定義一個物流Context類
- 第三,實現(xiàn)各種狀態(tài)類
- 第四, 客戶端使用
- 技術(shù)要點總結(jié)
- 優(yōu)缺點
- 優(yōu)點
- 缺點
- 狀態(tài)模式與策略模式
- 總結(jié)
概述
狀態(tài)模式在日常開發(fā)中是一個非常實用的模式,可以將你的代碼逼格迅速提升一個檔次,所以讓我們開始今天的卓越之旅吧。
類型
行為型(behavioral)
難度
3顆星
定義
當(dāng)一個對象內(nèi)在狀態(tài)改變時允許改變其行為,這個對象看起來像是改變了其類。
定義對于初學(xué)者沒啥用,因為字都認(rèn)識卻無法理解其中的含義。必須等學(xué)完了,回過頭來看才能更加深刻的理解其含義
使用場景
你發(fā)現(xiàn)你的代碼里面存在一個很長的if else列表,而這些分支都是因為不同狀態(tài)下執(zhí)行的操作不一樣時考慮使用此模式
UML類圖
照例先上一張俺手撕的UML類圖
從上圖可見,狀態(tài)模式共有3個角色
- State
是一個接口,封裝了狀態(tài)及其行為
- ConcreteState X
State的實現(xiàn)類,表示具體的狀態(tài)
- Context
保持并切換各個狀態(tài),其持有一個State的引用。它將依賴狀態(tài)的各種操作委托給不同的狀態(tài)對象執(zhí)行。其負(fù)責(zé)與客戶端交互
實例
最近王二狗又要過生日了,近兩年他內(nèi)心中是非常抗拒過生日的,因為每過一個生日就意味著自己又老一歲,離被辭退的35歲魔咒又近了一步。可惜時間是不以人的意志為轉(zhuǎn)移的,任何人都阻止不了時間的流逝,所以該過還的過。令二狗比較欣慰的時,這次過生日老婆送了他一個自己一直想要的機械鍵盤作為生日禮物… 翠花于是在二狗生日前3天在京東上下了一個單…
自從下單以來,二狗天天看物流狀態(tài)信息,心心念念著自己的機械鍵盤快點到…
這個物流系統(tǒng)就很適合使用狀態(tài)模式來開發(fā),因為此過程存在很多不同的狀態(tài),例如接單,出庫,運輸,送貨,收貨,評價等等。而訂單在每個不同的狀態(tài)下的操作可能都不一樣,例如在接單狀態(tài)下,商家就需要通知倉庫揀貨,通知用戶等等操作,其他狀態(tài)類似
下面是實例的UML類圖
第一,定義一個狀態(tài)接口
此接口定義各個狀態(tài)的統(tǒng)一操作接口
public interface LogisticsState {void doAction(JdLogistics context); }第二,定義一個物流Context類
此類持有一個LogisticsState 的引用,負(fù)責(zé)在流程中保持并切換狀態(tài)
public class JdLogistics {private LogisticsState logisticsState;public void setLogisticsState(LogisticsState logisticsState) {this.logisticsState = logisticsState;}public LogisticsState getLogisticsState() {return logisticsState;}public void doAction(){Objects.requireNonNull(logisticsState);logisticsState.doAction(this);} }第三,實現(xiàn)各種狀態(tài)類
- 接單狀態(tài)類,其需要實現(xiàn)LogisticsState接口
- 出庫狀態(tài)類
依次類推,可以建立任意多個狀態(tài)類
第四, 客戶端使用
public class StateClient {public void buyKeyboard() {//狀態(tài)的保持與切換者JdLogistics jdLogistics = new JdLogistics();//接單狀態(tài)OrderState orderState = new OrderState();jdLogistics.setLogisticsState(orderState);jdLogistics.doAction();//出庫狀態(tài)ProductOutState productOutState = new ProductOutState();jdLogistics.setLogisticsState(productOutState);jdLogistics.doAction();//運輸狀態(tài)TransportState transportState = new TransportState();jdLogistics.setLogisticsState(transportState);jdLogistics.doAction();} }輸出結(jié)果:
商家已經(jīng)接單,正在處理中... 商品已經(jīng)出庫... 商品正在運往天津分發(fā)中心可見,我們將每個狀態(tài)下要做的具體動作封裝到了每個狀態(tài)類中,我們只需要切換不同的狀態(tài)即可。如果不使用狀態(tài)模式,我們的代碼中可能會出現(xiàn)很長的if else列表,這樣就不便于擴展和修改了。
技術(shù)要點總結(jié)
- 必須要有一個Context類,這個類持有State接口,負(fù)責(zé)保持并切換當(dāng)前的狀態(tài)。
- 狀態(tài)模式?jīng)]有定義在哪里進(jìn)行狀態(tài)轉(zhuǎn)換,本例是在Context類進(jìn)行的,也有人在具體的State類中轉(zhuǎn)換
當(dāng)使用Context類切換狀態(tài)時,狀態(tài)類之間互相不認(rèn)識,他們直接的依賴關(guān)系應(yīng)該由客戶端負(fù)責(zé)。
例如,只有在接單狀態(tài)的操作完成后才應(yīng)該切換到出庫狀態(tài),那么出庫狀態(tài)就對接單狀態(tài)有了依賴,這個依賴順序應(yīng)該由客戶端負(fù)責(zé),而不是在狀態(tài)內(nèi)判斷。
當(dāng)使用具體的State類切換時,狀態(tài)直接就可能互相認(rèn)識,一個狀態(tài)執(zhí)行完就自動切換到了另一個狀態(tài)去了
優(yōu)缺點
優(yōu)點
- 增強了程序的可擴展性,因為我們很容易添加一個State
- 增強了程序的封裝性,每個狀態(tài)的操作都被封裝到了一個狀態(tài)類中
缺點
類變多了
狀態(tài)模式與策略模式
狀態(tài)模式與策略模式的UML類圖都是一樣的,從表面上看他們非常相似。特別是將狀態(tài)切換任務(wù)放在Context中做的時候就更像了,但是其背后的思想?yún)s非常不同。
- 策略模式定義了一組可互相代替的算法,這一組算法對象完成的是同一個任務(wù),只是使用的方式不同,例如同樣是億萬富翁,馬云通過賣東西實現(xiàn),而王思聰通過繼承實現(xiàn)。
- 狀態(tài)模式不同的狀態(tài)完成的任務(wù)完全不一樣。
總結(jié)
設(shè)計模式值得你刻意練習(xí)!
最后,如果你從本文中有所收獲,可否點贊轉(zhuǎn)發(fā)支持一下博主,你小小的鼓勵,是激發(fā)博主持續(xù)寫作的動力…
GitHub源碼地址:design-patterns
總結(jié)
以上是生活随笔為你收集整理的秒懂设计模式之状态模式(State Pattern)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 百度-嘟嘟熊买帽子
- 下一篇: asp.net ajax控件工具集 Au