JAVA設計模式之 狀態模式【State Pattern】,設計模式pattern
一、概述
當系統中某個對象存在多個狀態,這些狀態之間可以進行轉換,而且對象在不同狀態下行為不相同時可以使用狀態模式。狀態模式將一個對象的狀態從該對象中分離出來,封裝到專門的狀態類中,使得對象狀態可以靈活變化。狀態模式是一種對象行為型模式。
二、適用情境
用於解決系統中複雜物件的多種狀態轉換以及不同狀態下行為的封裝問題。簡單說就是處理對象的多種狀態及其相互轉換。
三、UML類圖
四、參與者
1>、AbstractState(抽象狀態類):
在抽象狀態類中定義申明了不同狀態下的行為抽象方法,而由子類(不同的狀態子類)中實現不同的行為操作。
2>、ConcreteState(實現具體狀態下行為的狀態子類):
抽象狀態類的子類,每一個子類實現一個與環境類(Context)的一個狀態相關的行為,每一個具體的狀態類對應環境的一種具體狀態,不同的具體狀態其行為有所不同。
3>、Context(擁有狀態物件的環境類):
擁有狀態屬性,因環境的多樣性,它可擁有不同的狀態,且在不同狀態下行為也不一樣。在環境類中維護一個抽象的狀態執行個體,這個執行個體定義當前環境的狀態(setState()方法),而將具體的狀態行為分離出來由不同的狀態子類去完成。
五、用例學習
1、抽象狀態類:State.java
/** * JAVA設計模式之 狀態模式 * 抽象狀態類 * @author lvzb.software@qq.com * */public abstract class State {/** * 狀態行為抽象方法,由具體的狀態子類去實現不同的行為邏輯 */public abstract void Behavior();}2、具體狀態子類A:ConcreteStateA.java
/** * 具體的狀態子類A * @author lvzb.software@qq.com */public class ConcreteStateA extends State {@Overridepublic void Behavior() {// 狀態A 的業務行為, 及當為該狀態下時,能幹什麼 // 如:手機在未欠費停機狀態下, 能正常撥打到電話System.out.println("手機在未欠費停機狀態下, 能正常撥打到電話");}}3、具體狀態子類B:ConcreteStateB.java
/** * 具體的狀態子類B * @author lvzb.software@qq.com * */public class ConcreteStateB extends State {@Overridepublic void Behavior() {// 狀態B 的業務行為, 及當為該狀態下時,能幹什麼// 如:手機在欠費停機狀態下, 不 能撥打到電話System.out.println("手機在欠費停機狀態下, 不能撥打到電話");}}4、擁有狀態物件的環境類:Context.java
/** * 環境/上下文類<br/> * 擁有狀態物件,且可以完成狀態間的轉換 [狀態的改變/切換 在環境類中實現] * @author lvzb.software@qq.com * */public class Context {// 維護一個抽象狀態物件的引用private State state;/* * 類比手機的話費屬性<br/> * 環境狀態如下: * 1>、當 bill >= 0.00$ : 狀態正常 還能撥打到電話 * 2>、當 bill < 0.00$ : 手機欠費 不能撥打到電話 */private double bill;/** * 環境處理函數,調用狀態執行個體行為 完成商務邏輯<br/> * 根據不同的狀態執行個體引用 在不同狀態下處理不同的行為 */public void Handle(){checkState();state.Behavior();}/** * 檢查環境狀態:狀態的改變/切換 在環境類中實現 */private void checkState(){if(bill >= 0.00){setState(new ConcreteStateA());} else {setState(new ConcreteStateB());}}/** * 設定環境狀態<br/> * 私人方法,目的是 讓環境的狀態由系統內容自身來控制/切換,外部使用者無需關心環境內部的狀態 * @param state */private void setState(State state){this.state = state;}public double getBill() {return bill;}public void setBill(double bill) {this.bill = bill;}}5、測試用戶端調用類:Client.java
public class Client {public static void main(String[] args) {Context context = new Context();context.setBill(5.50);System.out.println("當前話費餘額:" + context.getBill() + "$");context.Handle();context.setBill(-1.50);System.out.println("當前話費餘額:" + context.getBill() + "$");context.Handle();context.setBill(50.00);System.out.println("當前話費餘額:" + context.getBill() + "$");context.Handle();}}6、程式運行結果:
當前話費餘額:5.5$手機在未欠費停機狀態下, 能正常撥打到電話當前話費餘額:-1.5$手機在欠費停機狀態下, 不能撥打到電話當前話費餘額:50.0$手機在未欠費停機狀態下, 能正常撥打到電話
六、擴充
狀態模式中 關於狀態的切換有兩種不同的實現方式
方式一:狀態的改變/切換 在環境類中實現。 如上面的用例代碼Context類中的checkState()方法。
/** * 檢查環境狀態:狀態的改變/切換 在環境類中實現 */private void checkState(){if(bill >= 0.00){setState(new ConcreteStateA());} else {setState(new ConcreteStateB());}}
方式二:狀態的改變/切換 在具體的狀態子類中實現。
實現步驟如下:
1> 在環境類Context類中 初始化一個狀態執行個體對象,並將環境Context對象作為子類狀態的構造參數傳遞到具體的狀態子類執行個體中。
如在Context.java類中:
// 設定初始狀態this.state = new ConcreteStateA(this);
2> 在具體的子類狀態類中根據構造進來的context對象,通過調用context對象的屬性值進行商務邏輯判斷 進行狀態的檢查和切換。
如在 具體的狀態子類ConcreteStateA.java類中:
/** * 具體的狀態子類A * @author lvzb.software@qq.com */public class ConcreteStateA extends State {private Context ctx; public ConcreteStateA(Context context){ ctx = context; }@Overridepublic void Behavior() {// 狀態A 的業務行為, 及當為該狀態下時,能幹什麼 // 如:手機在未欠費停機狀態下, 能正常撥打到電話System.out.println("手機在未欠費停機狀態下, 能正常撥打到電話");checkState();}/** * 檢查狀態 是否需要進行狀態的轉換<br/> * 狀態的切換由具體狀態子類中實現 */private void checkState(){if (ctx.getBill() < 0.00) {ctx.setState(new ConcreteStateB(ctx));}}}