【設計模式(20)】行為型模式之狀態模式
阿新 • • 發佈:2021-07-01
個人學習筆記分享,當前能力有限,請勿貶低,菜鳥互學,大佬繞道
如有勘誤,歡迎指出和討論,本文後期也會進行修正和補充
人都有喜怒哀樂,在不同的情緒下,我們可能會作出不同的行為,進而影響外界事物;而外界事物也可能影響我們的情緒,導致我們作出不同的行為(完美閉環)
開發中的物件,有時候也會根據不同的情況作出不同的行為,而物件與外部事件互動的時候,也可能改變自身的狀態,進而行為也發生改變
對於有多種狀態的物件,傳統的解決方案是列舉所有的情況,使用條件判斷語句if-else
或者switch-case
來判斷,但對於複雜的狀態判斷,則會顯得過於臃腫和混亂。而且每次新增狀態都需要新增一個判斷,擴充套件性差
狀態模式就是為了解決這種問題而出現的,通過將狀態相關的判斷邏輯提取出來,使用不同的類進行表示,根據不同的狀態選擇相應的類來進行處理。
1.介紹
適用目的:允許物件在內部狀態發生改變時改變它的行為
主要解決:物件的行為依賴於它的狀態(屬性),並且可以根據它的狀態改變而改變它的相關行為。
何時使用:程式碼中包含大量與物件狀態有關的條件語句。
如何解決:將各種具體的狀態類抽象出來,單獨成為類。
關鍵程式碼:定義統一的介面,根據不同的狀態進行不同實現。
應用例項:系統和應用的低負載/高負載/超載狀態;安裝程式的下一步;
優點:
- 結構清晰,狀態模式將與特定狀態相關的行為區域性化到一個狀態中,並且將不同狀態的行為分割開來,滿足“單一職責原則”。
- 將狀態轉換顯示化,減少物件間的相互依賴。將不同的狀態引入獨立的物件中會使得狀態轉換變得更加明確,且減少物件間的相互依賴。
- 狀態類職責明確,有利於程式的擴充套件。通過定義新的子類很容易地增加新的狀態和轉換。
缺點:
- 狀態模式的使用必然會增加系統的類與物件的個數。
- 狀態模式的結構與實現都較為複雜,如果使用不當會導致程式結構和程式碼的混亂。
- 狀態模式對開閉原則的支援並不太好,對於可以切換狀態的狀態模式,增加新的狀態類需要修改那些負責狀態轉換的原始碼,否則無法切換到新增狀態,而且修改某個狀態類的行為也需要修改對應類的原始碼
使用場景:
- 行為隨狀態改變而改變的場景。
- 條件、分支語句的代替者。
2.結構
狀態模式包含以下主要角色
- 環境類(Context):也稱為上下文,它定義了客戶端需要的介面,內部維護一個當前狀態,並負責具體狀態的切換。
- 抽象狀態(State):定義一個介面,用以封裝環境物件中的特定狀態所對應的行為,可以有一個或多個行為。
- 具體狀態(Concrete State):實現抽象狀態所對應的行為,並且在需要的情況下進行狀態切換。
3.步驟
-
建立環境類
class Context { private State state; public Context(State state) { this.state = state; } public State getState() { return state; } public void setState(State state) { this.state = state; } public void handle() { state.handle(this); } }
-
建立抽象狀態
interface State { void handle(Context context); }
-
建立具體狀態
class StateA implements State { @Override public void handle(Context context) { System.out.println("change stateA to stateB"); // 狀態變為B context.setState(new StateB()); } } class StateB implements State { @Override public void handle(Context context) { System.out.println("change stateB to stateC"); // 狀態變為C context.setState(new StateC()); } } class StateC implements State { @Override public void handle(Context context) { System.out.println("change stateC to stateA"); // 狀態變為C context.setState(new StateA()); } }
測試程式碼
public class StateTest {
public static void main(String[] args) {
Context context = new Context(new StateA()); // 建立環境,初始狀態為A
context.handle(); // 第1次變更,A變為B
context.handle(); // 第2次變更,B變為C
context.handle(); // 第3次變更,C變為A
context.handle(); // 第4次變更,A變為B
}
}
執行結果
4.例項
模擬場景如下
- 分數包括三種評級
- 不及格:小於60分
- 及格:大於等於60且小於90
- 優秀:大於等於90
- 對分數進行加減,獲取當前的分數和評級
程式碼如下
package com.company.designPattern.state;
import java.util.Scanner;
public class ScoreStateTest {
public static void main(String[] args) {
ScoreContext account = new ScoreContext();
Scanner input = new Scanner(System.in);
System.out.println("學生成績狀態測試:");
while (true) {
System.out.print("請輸入分數變化:");
int num = input.nextInt();
account.add(num);
}
}
}
//環境類
class ScoreContext {
private AbstractState state;
ScoreContext() {
state = new LowState(this);
}
public void setState(AbstractState state) {
this.state = state;
}
public AbstractState getState() {
return state;
}
public void add(int score) {
state.addScore(score);
}
}
//抽象狀態類
abstract class AbstractState {
protected ScoreContext context; //環境
protected String stateName; //狀態名
protected int score; //分數
public abstract void checkState(); //檢查當前狀態
public void addScore(int x) {
score += x;
System.out.print("加上:" + x + "分,\t當前分數:" + score);
checkState();
System.out.println("分,\t當前狀態:" + context.getState().stateName);
}
}
//具體狀態類:不及格
class LowState extends AbstractState {
public LowState(ScoreContext h) {
context = h;
stateName = "不及格";
score = 0;
}
public LowState(AbstractState state) {
context = state.context;
stateName = "不及格";
score = state.score;
}
public void checkState() {
if (score >= 90) {
context.setState(new HighState(this));
} else if (score >= 60) {
context.setState(new MiddleState(this));
}
}
}
//具體狀態類:中等
class MiddleState extends AbstractState {
public MiddleState(AbstractState state) {
context = state.context;
stateName = "及格";
score = state.score;
}
public void checkState() {
if (score < 60) {
context.setState(new LowState(this));
} else if (score >= 90) {
context.setState(new HighState(this));
}
}
}
//具體狀態類:優秀
class HighState extends AbstractState {
public HighState(AbstractState state) {
context = state.context;
stateName = "優秀";
score = state.score;
}
public void checkState() {
if (score < 60) {
context.setState(new LowState(this));
} else if (score < 90) {
context.setState(new MiddleState(this));
}
}
}
執行結果
後記
感覺是個很有意思的東西,非常巧妙的達到了多狀態和行為切換的目的,同時保證了高效能和低耦合
作者:Echo_Ye
WX:Echo_YeZ
Email :[email protected]
個人站點:在搭了在搭了。。。(右鍵 - 新建資料夾)