大話設計模式九:狀態模式
一.模式定義
物件行為型模式。
狀態模式:允許一個物件在其內部狀態改變時改變它的行為,物件看起來似乎修改了它的類。
State Pattern: Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.
二.模式要素
Context: 環境類
State: 抽象狀態類
ConcreteState: 具體狀態類
三.舉例說明
我們舉一個工作者每天工作狀態的例子。想象一下有個緊急專案要上線,領導要求你一天24小時都不間斷地工作,那你的狀態可能是下面這樣。
早晨狀態(9:00-12:00):早晨工作效率很高
下午狀態(12:00-18:00):下午有點瞌睡
晚上狀態(18:00-21:00):晚上效率較高
垂死掙扎狀態(21:00-9:00):還加班,感覺身體被掏空
隨著時間的變化,工作者的工作狀態也發生著改變。那怎麼用程式碼表示這樣他的場景呢,狀態模式來幫忙。
UML圖如下所示:
四.模式例項
Worker.java
package state; public class Worker { private IState currentState; private int time; public Worker() { currentState = new MorningState(); } public void setCurrentState(IState currentState) { this.currentState = currentState; } public int getTime() { return time; } public void setTime(int time) { this.time = time; } public void showState() { currentState.showWorkState(this); } }
IState.java
package state;
public interface IState {
public void showWorkState(Worker worker);
}
MorningState.java
package state; public class MorningState implements IState { @Override public void showWorkState(Worker worker) { int time = worker.getTime(); if (time >= 9 && time < 12) { System.out.println("早晨工作效率很高"); } else { worker.setCurrentState(new AfternoonState()); worker.showState(); } } }
AfternoonState.java
package state;
public class AfternoonState implements IState {
@Override
public void showWorkState(Worker worker) {
int time = worker.getTime();
if(time >= 12 && time < 18) {
System.out.println("下午有點瞌睡");
} else {
worker.setCurrentState(new NightState());
worker.showState();
}
}
}
NightState.java
package state;
public class NightState implements IState {
@Override
public void showWorkState(Worker worker) {
int time = worker.getTime();
if (time >= 18 && time < 21) {
System.out.println("晚上效率較高");
} else {
worker.setCurrentState(new DyingState());
worker.showState();
}
}
}
DyingState.java
package state;
public class DyingState implements IState {
@Override
public void showWorkState(Worker worker) {
System.out.println("還加班,感覺身體被掏空");
}
}
Main.java
package state;
public class Main {
public static void main(String[] args) {
Worker worker = new Worker();
worker.setTime(10);
worker.showState();
worker.setTime(13);
worker.showState();
worker.setTime(19);
worker.showState();
worker.setTime(23);
worker.showState();
}
}
執行結果:
五.總結
1.狀態模式的優點
(1)封裝了轉換規則。
(2)列舉可能的狀態,在列舉狀態之前需要確定狀態種類。
(3)將所有與某個狀態有關的行為放到一個類中,並且可以方便地增加新的狀態,只需要改變物件狀態即可改變物件的行為。
(4)允許狀態轉換邏輯與狀態物件合成一體,而不是某一個巨大的條件語句塊。
(5)可以讓多個環境物件共享一個狀態物件,從而減少系統中物件的個數。
2.狀態模式的缺點
(1)狀態模式的使用必然會增加系統類和物件的個數。
(2)狀態模式的結構與實現都較為複雜,如果使用不當將導致程式結構和程式碼的混亂。
(3)狀態模式對“開閉原則”的支援並不太好,對於可以切換狀態的狀態模式,增加新的狀態類需要修改那些負責狀態轉換的原始碼,否則無法切換到新增狀態;而且修改某個狀態類的行為也需修改對應類的原始碼。
3.狀態模式的適用場景
(1)物件的行為依賴於它的狀態(屬性)並且可以根據它的狀態改變而改變它的相關行為。
(2)程式碼中包含大量與物件狀態有關的條件語句,這些條件語句的出現,會導致程式碼的可維護性和靈活性變差,不能方便地增加和刪除狀態,使客戶類與類庫之間的耦合增強。在這些條件語句中包含了物件的行為,而且這些條件對應於物件的各種狀態。