iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 26
0

文同步分享於個人blog

  • 定義


有狀態的物件,把複雜的邏輯判斷分配到不同的狀態物件中,允許狀態物件在其內部狀態發生改變時改變行為。

比如說,人在開心的時候會開懷大笑,在傷心的時候會哭泣,在生氣的時候會想打人...等等,根據不同的狀態,會有不同的行為。而在系統中,通常這個行為會用if-else去做判斷,對應不同的情況去做對應的處理。但如果物件的狀態很多,程式碼會變得很複雜,而且當要新增狀態時,要更改if-else的邏輯,這樣就違背了開閉原則,不利於擴充。

而狀態模式的解決方式就是,控制一個物件狀態的條件過於複雜時,把相關判斷娜及取出,放到一系列的狀態類別中,就可以簡化原本複雜的邏輯。

  • State Pattern 成員


成員 功用
Context(環境) 定義Client的接口,維護目前的狀態,並將狀態的操作委託給目前狀態物件來處理。
State(狀態) 定義一個接口,用來封裝Context中特定狀態所對應的行為。
ConcreteState(實體狀態) 實現State所定義的方法。

p

  • State Pattern 實作


可以試想,今天到銀行要辦一張信用卡,申辦的步驟非常的煩瑣如下:

填寫資料後
1. 業務審核:資料是否完整。
2. 行員審核:查看帳戶及信用卡費是否有按時繳交。
3. 信用卡部審核:調閱聯徵紀錄查詢分數。

以上是簡略的步驟,分成ABC三階段。接著就來實作申請信用卡時的步驟。

首先先將抽象狀態以及實體狀態建立起來,在每個不同的狀態中,會有不同的邏輯實作。


//抽象狀態
abstract class State {
    public abstract boolean Handle(Context context, boolean status);
}
//實體狀態A:業務審核
class ConcreteStateA extends State {
    public boolean Handle(Context context, boolean status) {
        if (status){
            System.out.println("資料填寫完整,業務審核通過,準備進入行員審核。");
            context.setState(new ConcreteStateB());
        } else {
            System.out.println("業務審核中。");
        }
        return false;
    }
}
//實體狀態B:行員審核
class ConcreteStateB extends State {
    public boolean Handle(Context context, boolean status) {
        if (status){
            System.out.println("行員審核通過,準備進入信用卡部審核。");
            context.setState(new ConcreteStateC());
        } else {
            System.out.println("行員審核中。");
        }
        return false;
    }
}
//實體狀態C:信用卡部審核
class ConcreteStateC extends State {
    public boolean Handle(Context context, boolean status) {
        if (status){
            System.out.println("信用卡部審核通過,寄送信用卡。");
            return true;
        } else {
            System.out.println("信用卡部審核中。");
            return false;
        }
    }
}

接著建立Context環境類,要在內部定義初始狀態,這個範例的初始狀態是業務審核ConcreteStateA。

//環境類
class Context {
    private State state;
    // 定義環境類的初始狀態
    public Context() {
        this.state = new ConcreteStateA();
    }
    //設定狀態
    public void setState(State state) {
        this.state = state;
    }
    //讀取狀態
    public State getState() {
        return(state);
    }
    //處理請求
    public boolean Handle(boolean status) {
        return state.Handle(this, status);
    }
}

最後在Client來使用看看


import java.util.*;
public class StatePatternClient{
    public static void main(String[] args) {       
        Context context = new Context();    //建立環境
        
        Scanner scanner = new Scanner(System.in);
        boolean end = false;
        System.out.println("申請已送出,請等待審核結果。");
        while (!end){
            System.out.println("請輸入選項(1:審核通過;2:繼續審核;3:結束程式):");
            int num = scanner.nextInt();
            if (num == 1){
                end = context.Handle(true);    //處理請求
            } else if (num == 2){
                end = context.Handle(false);    //處理請求
            } else if (num == 3){
                end = true;
            } else {
                System.out.println("請輸入正確指令" );
            }
        }
    }
}

  • 小結


State Pattern的目標

有狀態的物件,把複雜的邏輯判斷分配到不同的狀態物件中,允許狀態物件在其內部狀態發生改變時改變行為。

State Pattern的成員
Context:定義Client的接口,維護目前的狀態,並將狀態的操作委託給目前狀態物件來處理。
State:定義一個接口,用來封裝Context中特定狀態所對應的行為。
ConcreteState:實現State所定義的方法。
State Pattern的優缺點
優點
1. 減少物件之間的依賴性。
2. 利於系統的擴中。
3. 定義新的子類別可以很容易的新增新狀態。
缺點
1. 增加系統的類別及物件的個數。
2. 結構與實作都相對複雜。
State Pattern的使用時機
1. 物件的行為取決於他的狀態,並必須要執行時根據狀態改變他的行為時。
2. 一個操作具有龐大的分支結構,且這些分支決定物件的狀態時。
  • 範例程式碼


範例:State Pattern 實作

  • References


状态模式(详解版)


上一篇
[Day25] 中介者模式 | Mediator Pattern
下一篇
[Day27] 備忘錄模式 | Memento Pattern
系列文
從生活中認識Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言