目錄
- 1. 說明
- 2. 應(yīng)用場景
- 3. 結(jié)構(gòu)圖
- 4. 構(gòu)成
- 5. 優(yōu)缺點(diǎn)
- 5.1 優(yōu)點(diǎn)
- 5.2 缺點(diǎn)
- 6. java示例
- 6.1 非狀態(tài)模式
- 6.1.1 問題分析
- 6.1.2 接口類
- 6.1.2 實(shí)現(xiàn)類
- 6.1.3 客戶端
- 6.1.4 結(jié)果截圖
- 6.2 狀態(tài)模式
- 6.2.1 抽象狀態(tài)類
- 6.2.2 狀態(tài)類
- 6.2.3 上下文類
- 6.2.4 上下文類
1. 說明
- 1.允許一個(gè)對象在其內(nèi)部狀態(tài)改變時(shí)改變它的行為。
- 2.對象看起來似乎修改了它的類。
- 3.對有狀態(tài)的對象,把復(fù)雜的“判斷邏輯”提取到不同的狀態(tài)對象中,允許狀態(tài)對象在其內(nèi)部狀態(tài)發(fā)生改變時(shí)改變其行為。
2. 應(yīng)用場景
- 1.一個(gè)對象的行為決定于它的狀態(tài),并且它必須在運(yùn)行時(shí)刻根據(jù)狀態(tài)改變它的行為。
- 2.一個(gè)操作中含有龐大的多分支的條件語句,且這些分支依賴于該對象的狀態(tài)。這個(gè)狀態(tài)常用一個(gè)或多個(gè)枚舉常量表示。通常,有多個(gè)操作包含這一相同的條件結(jié)構(gòu)。State模式將每一個(gè)條件分支放入一個(gè)獨(dú)立的類中。這使得開發(fā)者可以根據(jù)對象自身的情況將對象的狀態(tài)作為一個(gè)對象,這一對象可以不依賴于其他對象獨(dú)立變化。
3. 結(jié)構(gòu)圖

4. 構(gòu)成
- 1.環(huán)境角色:Context(上下文)定義客戶端感興趣的接口;維護(hù)一個(gè)ConcreteState子類的實(shí)例,這個(gè)實(shí)例定義當(dāng)前狀態(tài)
- 2.抽象狀態(tài)角色:State(狀態(tài))定義一個(gè)接口以封裝與Context的一個(gè)特定狀態(tài)相關(guān)的行為
- 3.具體狀態(tài)角色:ConcreteState(具體狀態(tài)子類)每個(gè)子類實(shí)現(xiàn)與Context的一個(gè)狀態(tài)相關(guān)的行為
5. 優(yōu)缺點(diǎn)
5.1 優(yōu)點(diǎn)
- 1.將所有與某個(gè)狀態(tài)有關(guān)的行為放到一個(gè)類中,并且可以方便地增加新的狀態(tài),只需要改變對象狀態(tài)即可改變對象的行為。
- 2.允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對象合成一體,而不是某一個(gè)巨大的條件語句塊。
5.2 缺點(diǎn)
- 1.狀態(tài)模式的使用必然會增加系統(tǒng)類和對象的個(gè)數(shù)。
- 2.狀態(tài)模式的結(jié)構(gòu)與實(shí)現(xiàn)都較為復(fù)雜,如果使用不當(dāng)將導(dǎo)致程序結(jié)構(gòu)和代碼的混亂。
- 3.狀態(tài)模式對"開閉原則"的支持并不太好。
6. java示例
6.1 非狀態(tài)模式
6.1.1 問題分析
- 1.使用了大量的switch case這樣的判斷(if else也是一樣),使程序的可閱讀性變差
- 2.擴(kuò)展性差,如果新加了一種狀態(tài),則需要修改判斷邏輯
6.1.2 接口類
package com.learning.state.before;/*** 電梯接口*/
public interface ILift {//定義四個(gè)電梯狀態(tài)的常量/*** 打開狀態(tài)*/int OPENING_STATE = 1;/*** 關(guān)閉狀態(tài)*/int CLOSING_STATE = 2;/*** 運(yùn)行狀態(tài)*/int RUNNING_STATE = 3;/*** 停止?fàn)顟B(tài)*/int STOPPING_STATE = 4;//設(shè)置電梯狀態(tài)的功能void setState(int state);//電梯操作功能void open();//電梯關(guān)閉功能void close();//電梯運(yùn)行功能void run();//電梯停止功能void stop();
}
6.1.2 實(shí)現(xiàn)類
package com.learning.state.before;/*** @Description 電梯類**/
public class Lift implements ILift{//當(dāng)前電梯狀態(tài)private int state;@Overridepublic void setState(int state) {this.state = state;}@Overridepublic void open() {switch(state){//如果當(dāng)前電梯狀態(tài)是開啟狀態(tài)case OPENING_STATE://什么都不做break;//如果當(dāng)前電梯狀態(tài)是關(guān)閉狀態(tài),打開電梯case CLOSING_STATE:System.out.println("電梯打開了");// 設(shè)置當(dāng)前電梯狀態(tài)為開啟狀態(tài)setState(OPENING_STATE);break;//如果當(dāng)前電梯狀態(tài)是運(yùn)行狀態(tài)case RUNNING_STATE://什么都不做break;//如果當(dāng)前電梯狀態(tài)是開啟狀態(tài),打開電梯case STOPPING_STATE:System.out.println("電梯打開了");setState(OPENING_STATE);break;}}@Overridepublic void close() {switch(this.state) {case OPENING_STATE://只有開門狀態(tài)可以關(guān)閉電梯門System.out.println("電梯關(guān)門了");//關(guān)門之后電梯就是關(guān)閉狀態(tài)了this.setState(CLOSING_STATE);break;case CLOSING_STATE://已經(jīng)是關(guān)門狀態(tài),不能關(guān)門//什么都不做break;case RUNNING_STATE://運(yùn)行時(shí)電梯門是關(guān)著的,不能關(guān)門//什么都不做break;case STOPPING_STATE://停止時(shí)電梯也是關(guān)著的,不能關(guān)門//什么都不做break;}}@Overridepublic void run() {switch(this.state) {case OPENING_STATE://電梯不能開著門運(yùn)行break;case CLOSING_STATE://門關(guān)了,可以運(yùn)行了System.out.println("電梯運(yùn)行了");//設(shè)置為運(yùn)行狀態(tài)this.setState(RUNNING_STATE);break;case RUNNING_STATE://已經(jīng)是運(yùn)行狀態(tài)了break;case STOPPING_STATE:System.out.println("電梯運(yùn)行了");//設(shè)置為運(yùn)行狀態(tài)this.setState(RUNNING_STATE);break;}}@Overridepublic void stop() {switch(this.state) {case OPENING_STATE:// 開門的電梯已經(jīng)是是停止的了(正常情況下)break;case CLOSING_STATE:// 關(guān)門時(shí)才可以停止System.out.println("電梯停止了");this.setState(STOPPING_STATE);break;case RUNNING_STATE:// 運(yùn)行時(shí)當(dāng)然可以停止了System.out.println("電梯停止了");this.setState(STOPPING_STATE);break;case STOPPING_STATE:break;}}
}
6.1.3 客戶端
package com.learning.state.before;/*** 客戶端*/
public class Client {public static void main(String[] args) {// 創(chuàng)建電梯對象Lift lift = new Lift();// 設(shè)置當(dāng)前電梯的狀態(tài)lift.setState(ILift.OPENING_STATE);// 打開lift.open();lift.close();lift.run();lift.stop();}
}
6.1.4 結(jié)果截圖

6.2 狀態(tài)模式
6.2.1 抽象狀態(tài)類
package com.learning.state.after;/*** 抽象狀態(tài)類*/
public abstract class LiftState {// 聲明環(huán)境角色類變量protected Context context;public void setContext(Context context){this.context = context;}// 電梯開啟操作public abstract void open();// 電梯關(guān)閉操作public abstract void close();// 電梯運(yùn)行操作public abstract void run();// 電梯停止操作public abstract void stop();
}
6.2.2 狀態(tài)類
package com.learning.state.after;/*** 開啟狀態(tài)類*/
public class OpeningState extends LiftState {// 當(dāng)前狀態(tài)要執(zhí)行的方法@Overridepublic void open() {System.out.println("電梯開啟");}@Overridepublic void close() {// 修改狀態(tài)super.context.setLiftState(Context.CLOSING_STATE);// 調(diào)用當(dāng)前狀態(tài)中的context中的close方法super.context.close();}@Overridepublic void run() {// 什么都不做}@Overridepublic void stop() {// 什么都不做}
}
package com.learning.state.after;/**
* 運(yùn)行狀態(tài)類
*/
public class RunningState extends LiftState {/*** 運(yùn)行的時(shí)候是不能開電梯門*/@Overridepublic void open() {// 什么都不做}/*** 運(yùn)行狀態(tài)的電梯,門不需要再關(guān)*/@Overridepublic void close() {// 什么都不做}/*** 運(yùn)行狀態(tài)下要實(shí)現(xiàn)的方法*/@Overridepublic void run() {System.out.println("電梯正在運(yùn)行");}/*** 運(yùn)行狀態(tài)可以停止*/@Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}
package com.learning.state.after;/*** 停止?fàn)顟B(tài)類*/
public class StoppingState extends LiftState {/*** 停止?fàn)顟B(tài)可以開門*/@Overridepublic void open() {// 狀態(tài)修改super.context.setLiftState(Context.OPENING_STATE);// 動(dòng)作委托為CloseState來執(zhí)行,也就是委托給ClosingState子類執(zhí)行這個(gè)動(dòng)作super.context.getLiftState().open();}/*** 可以關(guān)門,這個(gè)動(dòng)作不歸我執(zhí)行*/@Overridepublic void close() {// 狀態(tài)修改super.context.setLiftState(Context.CLOSING_STATE);// 動(dòng)作委托為CloseState來執(zhí)行,也就是委托給ClosingState子類執(zhí)行這個(gè)動(dòng)作super.context.getLiftState().close();}/*** 停止后,可以再跑起來*/@Overridepublic void run() {// 狀態(tài)修改super.context.setLiftState(Context.RUNNING_STATE);// 動(dòng)作委托為CloseState來執(zhí)行,也就是委托給ClosingState子類執(zhí)行這個(gè)動(dòng)作super.context.getLiftState().run();}/*** 停止方法執(zhí)行*/@Overridepublic void stop() {System.out.println("電梯停止了");}
}
package com.learning.state.after;/*** 關(guān)閉狀態(tài)類*/
public class ClosingState extends LiftState {/*** 電梯關(guān)閉狀態(tài)可以再打開*/@Overridepublic void open() {super.context.setLiftState(Context.OPENING_STATE);super.context.open();}/*** 電梯關(guān)閉狀態(tài)實(shí)現(xiàn)的動(dòng)作*/@Overridepublic void close() {System.out.println("電梯門關(guān)閉");}/*** 電梯關(guān)門之后啟動(dòng)*/@Overridepublic void run() {super.context.setLiftState(Context.RUNNING_STATE);super.context.run();}/*** 電梯門關(guān)著,但沒按樓層*/@Overridepublic void stop() {super.context.setLiftState(Context.STOPPING_STATE);super.context.stop();}
}
6.2.3 上下文類
package com.learning.state.after;public class Context {// 定義對應(yīng)狀態(tài)對象的常量public final static OpeningState OPENING_STATE = new OpeningState();public final static ClosingState CLOSING_STATE = new ClosingState();public final static RunningState RUNNING_STATE = new RunningState();public final static StoppingState STOPPING_STATE = new StoppingState();// 定義一個(gè)當(dāng)前電梯狀態(tài)變量private LiftState liftState;public LiftState getLiftState(){return liftState;}public void setLiftState(LiftState liftState){this.liftState = liftState;// 設(shè)置當(dāng)前狀態(tài)對象中的Context對象this.liftState.setContext(this);}public void open(){this.liftState.open();}public void close(){this.liftState.close();}public void run(){this.liftState.run();}public void stop(){this.liftState.stop();}}
6.2.4 上下文類
package com.learning.state.after;/*** 客戶端類*/
public class Client {public static void main(String[] args) {// 創(chuàng)建環(huán)境角色對象Context context = new Context();// 設(shè)置當(dāng)前電梯狀態(tài)context.setLiftState(Context.CLOSING_STATE);context.open();context.close();context.run();context.stop();}
}