設計模式系列之二十一:狀態模式
阿新 • • 發佈:2019-01-31
1.定義
當一個物件內在狀態改變時允許其改變行為,這個物件看起來像改變了其類。
2.通用類圖
角色介紹
- State 抽象狀態角色:介面或抽象類,負責物件狀態定義,並且封裝環境角色以實現狀態切換
- ConcreteState 具體狀態角色:每一個具體狀態必須完成兩個職責:本狀態的行為管理以及趨向狀態處理,通俗地講,就是本狀態下要做的事情,以及本狀態如何過度到其他狀態
- Context 環境角色:定義客戶端需要的介面,並且負責具體狀態的切換
3.通用原始碼
抽象狀態角色
public abstract class State {
//定義一個環境角色,提供子類訪問
protected Context context;
//設定環境角色
public void setContext(Context _context) {
this.context = _context;
}
//行為1
public abstract void handle1();
//行為2
public abstract void handle2();
}
抽象狀態中宣告一個環境角色,提供各個狀態類自行訪問,並且提供所有狀態的抽象行為,由各個實現類實現
具體狀態角色
public class ConcreteState1 extends State{
@Override
public void handle1() {
//本狀態下必須處理的邏輯
}
@Override
public void handle2() {
//設定當前狀態為stat2
super.context.setCurrentState(Context.STATE2);
//過渡到state2,由Context實現
super.context.handle2();
}
}
public class ConcreteState2 extends State {
@Override
public void handle1() {
//設定當前狀態為狀態1
super.context.setCurrentState(Context.STATE1);
//過渡到state1狀態,由context實現
super.context.handle1();
}
@Override
public void handle2() {
//本狀態下必須要處理的邏輯
}
}
具體狀態角色有兩個職責:處理本狀態必須完成的任務,決定是否可以過渡到其他狀態。
具體環境角色
public class Context {
//定義狀態
public final static State STATE1 = new ConcreteState1();
public final static State STATE2 = new ConcreteState2();
//當前狀態
private State currentState;
//獲得當前狀態
public State getCurrentState() {
return currentState;
}
//設定當前狀態
public void setCurrentState(State currentState) {
this.currentState = currentState;
//切換狀態
this.currentState.setContext(this);
}
//行為委託
public void handle1() {
this.currentState.handle1();
}
public void handle2() {
this.currentState.handle2();
}
}
環境角色有兩個不成文的約束:
- 把狀態物件宣告為靜態常量,有幾個狀態物件就宣告幾個靜態常量
- 環境角色具有狀態抽象角色定義的所有行為,具體執行使用委託方式
4.Demo
電梯是社會發展不可或缺的部分,電梯有開門、關門、執行、停止這幾個狀態。
但是電梯的每一個狀態都是有條件:
- 敞門狀態:按了電梯上下按鈕,門會開,在這個狀態下,電梯能做的只能是關門
- 閉門狀態:在此狀態下,只能是開門,停止,執行
- 執行狀態:在此狀態下,只能做停止。
停止狀態:這時,電梯可以繼續執行,也可以開門
這個時候如果用switch迴圈去判斷,可想而知邏輯有多雜亂。這還是正常情況,如果電梯出故障了呢,它在執行狀態時就不能做停止和開門操作。還要電梯維修的時候可以不開門,你也不能讓維修人修著修著電梯跑了不是。這樣你又要加多少判斷。這個時候引入狀態模式,就可以很方便地解決這個問題。具體程式碼,下次貼出。
5.優缺點
- 優點
- 結構清晰
- 避免了過多的switch…case或者if…else語句,提高了系統的可維護性
- 遵循設計原則
- 遵循了開閉原則和單一職責原則
- 封裝性非常好
- 狀態變換放置到類的內部實現,外部的呼叫不用知道類內部如何實現狀態和行為的切換
- 結構清晰
- 缺點
- 子類太多,會造成類膨脹。解決問題的辦法不止一種,我們也可以在資料庫建立一個狀態表,然後根據狀態執行響應的操作。
6.應用場景
- 行為隨狀態改變而改變的場景
- 這也是狀態模式的出發點,例如許可權設計,人員的不同狀態即使執行相同的行為結果也會不同
- 條件、分支判斷語句的替代者
- 程式中大量使用switch語句或者if語句導致 程式結構不清晰,邏輯混亂。
- 注意:
- 使用狀態模式時物件的狀態最好不超過5個