說明
記錄下學(xué)習(xí)設(shè)計模式-狀態(tài)模式的寫法。JDK使用版本為1.8版本。
State(狀態(tài))
意圖:允許一個對象在其內(nèi)部狀態(tài)改變時改變它的行為。
結(jié)構(gòu):
其中:
- Context(上下文)定義客戶感興趣的接口;維護(hù)一個ConcreteState子類的實(shí)例,這個實(shí)例定義當(dāng)前狀態(tài)。
- State(狀態(tài))定義一個接口以封裝與Context的一個特定狀態(tài)相關(guān)的行為。
- ConcreteState(具體狀態(tài)子類)每個子類實(shí)現(xiàn)與Context的一個狀態(tài)相關(guān)的行為。
適用性:
- 一個對象的行為決定于它的狀態(tài),并且它必須在運(yùn)行時刻根據(jù)狀態(tài)改變它的行為。
- 一個操作中含有龐大的多分支的條件語句,且這些分支依賴于該對象的狀態(tài)。
目錄
狀態(tài)模式示例類圖
[例]通過按鈕來控制一個電梯的狀態(tài),一個電梯有開門狀態(tài),關(guān)門狀態(tài),停止?fàn)顟B(tài),運(yùn)行狀態(tài)。每一種狀態(tài)改變,都有可能要根據(jù)其他狀態(tài)來更新處理。例如,如果電梯門現(xiàn)在處于運(yùn)行時狀態(tài),就不能進(jìn)行開門操作,而如果電梯門是停止?fàn)顟B(tài),就可以執(zhí)行開門操作。
以該UML類圖實(shí)現(xiàn)狀態(tài)模式示例。
抽象狀態(tài)類
package com.example.deesign_patterns.state;
//抽象狀態(tài)類
public abstract class LiftState {
//定義一個環(huán)境角色,也就是封裝狀態(tài)的變化引起的功能變化
//聲明環(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();
}
環(huán)境角色類
package com.example.deesign_patterns.state;
//環(huán)境角色類
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();
//定義一個當(dāng)前電梯狀態(tài)變量
private LiftState liftState;
public LiftState getLiftState() {
return liftState;
}
//設(shè)置當(dāng)前狀態(tài)對象
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();
}
}
電梯開啟狀態(tài)類
package com.example.deesign_patterns.state;
//電梯開啟狀態(tài)類
public class OpeningState extends LiftState{
//當(dāng)前狀態(tài)要執(zhí)行的方法
@Override
public void open() {
System.out.println("電梯開啟。。。");
}
@Override
public void close() {
//修改狀態(tài)
super.context.setLiftState(Context.CLOSING_STATE);
//調(diào)用當(dāng)前狀態(tài)中的context中的close方法
super.context.close();
}
@Override
public void run() {
//因?yàn)橐_啟,還沒到運(yùn)行所以什么都不做
}
@Override
public void stop() {
//因?yàn)橐_啟,還沒到停止所以什么都不做
}
}
電梯關(guān)閉狀態(tài)類
package com.example.deesign_patterns.state;
//電梯關(guān)閉狀態(tài)類
public class ClosingState extends LiftState{
//電梯門關(guān)閉再打開,很合理
@Override
public void open() {
//修改狀態(tài)
super.context.setLiftState(Context.OPENING_STATE);
//調(diào)用當(dāng)前狀態(tài)中的context中的open方法
super.context.open();
}
//當(dāng)前狀態(tài)要執(zhí)行的方法
@Override
public void close() {
System.out.println("電梯門關(guān)閉。。。");
}
//電梯門關(guān)了再運(yùn)行,很合理
@Override
public void run() {
//修改狀態(tài)
super.context.setLiftState(Context.RUNNING_STATE);
//調(diào)用當(dāng)前狀態(tài)中的context中的run方法
super.context.run();
}
//電梯門關(guān)著,我就不按樓層
@Override
public void stop() {
//修改狀態(tài)
super.context.setLiftState(Context.STOPPING_STATE);
//調(diào)用當(dāng)前狀態(tài)中的context中的stop方法
super.context.stop();
}
}
電梯運(yùn)行狀態(tài)類
package com.example.deesign_patterns.state;
//電梯運(yùn)行狀態(tài)類
public class RunningState extends LiftState{
//運(yùn)行的時候開電梯門,是不允許的,所以什么都不做
@Override
public void open() {
}
//運(yùn)行狀態(tài)電梯門肯定是關(guān)閉的,所以什么也不做
@Override
public void close() {
}
//當(dāng)前狀態(tài)要執(zhí)行的方法
@Override
public void run() {
System.out.println("電梯正在運(yùn)行。。。");
}
//既能運(yùn)行,必然要停止
@Override
public void stop() {
//修改狀態(tài)
super.context.setLiftState(Context.STOPPING_STATE);
//調(diào)用當(dāng)前狀態(tài)中的context中的stop方法
super.context.stop();
}
}
電梯停止?fàn)顟B(tài)類
package com.example.deesign_patterns.state;
//電梯停止?fàn)顟B(tài)類
public class StoppingState extends LiftState{
//電梯停止再開門,很合理
@Override
public void open() {
//修改狀態(tài)
super.context.setLiftState(Context.OPENING_STATE);
//動作委托為CloseState來執(zhí)行,也就是委托給ClosingState子類執(zhí)行這個歌動作
super.context.getLiftState().open();
}
//雖然可以關(guān)閉,但這個狀態(tài)不歸我管
@Override
public void close() {
//修改狀態(tài)
super.context.setLiftState(Context.CLOSING_STATE);
//動作委托為CloseState來執(zhí)行,也就是委托給ClosingState子類執(zhí)行這個歌動作
super.context.getLiftState().close();
}
//電梯停止再運(yùn)行起來,很合理
@Override
public void run() {
//修改狀態(tài)
super.context.setLiftState(Context.RUNNING_STATE);
//動作委托為CloseState來執(zhí)行,也就是委托給ClosingState子類執(zhí)行這個歌動作
super.context.getLiftState().run();
}
//當(dāng)前狀態(tài)要執(zhí)行的方法
@Override
public void stop() {
System.out.println("電梯停止了。。。");
}
}
測試類
package com.example.deesign_patterns.state;
//測試類
public class Client {
public static void main(String[] args) {
//創(chuàng)建環(huán)境角色對象
Context context=new Context();
//設(shè)置當(dāng)前電梯狀態(tài),這里設(shè)置為正在運(yùn)行狀態(tài)
context.setLiftState(new RunningState());
context.open();
context.close();
context.run();
context.stop();
}
}
好處:文章來源:http://www.zghlxwxcb.cn/news/detail-499713.html
- 將所有與某個狀態(tài)有關(guān)的行為放到一個類中,并且可以方便地增加新的狀態(tài),只需要改變對象狀態(tài)即可改變對象的行為。
- 允許狀態(tài)轉(zhuǎn)換邏輯與狀態(tài)對象合成一體,而不是某一個巨大的條件語句塊。
缺點(diǎn):文章來源地址http://www.zghlxwxcb.cn/news/detail-499713.html
- 狀態(tài)模式的使用必然會增加系統(tǒng)類和對象的個數(shù)。
- 狀態(tài)模式的結(jié)構(gòu)與實(shí)現(xiàn)都較為復(fù)雜,如果使用不當(dāng)將導(dǎo)致程序結(jié)構(gòu)和代碼的混亂。
- 狀態(tài)模式對開閉原則的支持并不太好。
到了這里,關(guān)于設(shè)計模式之狀態(tài)模式筆記的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!