1. 程式人生 > >大話設計模式九:狀態模式

大話設計模式九:狀態模式

一.模式定義

物件行為型模式。

狀態模式:允許一個物件在其內部狀態改變時改變它的行為,物件看起來似乎修改了它的類。
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)程式碼中包含大量與物件狀態有關的條件語句,這些條件語句的出現,會導致程式碼的可維護性和靈活性變差,不能方便地增加和刪除狀態,使客戶類與類庫之間的耦合增強。在這些條件語句中包含了物件的行為,而且這些條件對應於物件的各種狀態。