Java設計模式之從[遊戲中的兵種狀態轉換]分析狀態(State)模式

  假設我們正在做一個即時戰略遊戲,我們設計一個兵種,他在剛剛生產出來的時候是步兵,但是他可以切換武器,第一次切換會變成弓箭手,第二次切換會變成舉着盾牌的裝甲兵,第三次切換則又變成了步兵……如何實現這個切換的機制?我們一開始會想到,在步兵這個類中加入switch語句,然而這樣的話,代碼不利於擴展,不利於修改,這時我們就可以使用狀態模式了。

  狀態模式允許一個對象在其內部狀態改變時改變它的行爲。對象看起來似乎修改了它的類。

  在本例中,這個兵種有3個狀態——步兵、弓箭手和裝甲兵。我們將這3個狀態都繼承於同一個基類SoldierState,我們還需要定義一個兵種類來包含一個SoldierState對象,以便它是用來存儲這些狀態的,在本例中這個類的名字叫做KnightContext。先看Java代碼吧:

abstract class SoldierState {
    public abstract void show();
    protected void changeState(KnightContext knight, SoldierState soldierState){
        knight.changeState(soldierState);
    }
    public abstract void transform(KnightContext knight);
}

class KnightContext {
    SoldierState state;
    public KnightContext(){
        state = SwordState.getState();
    }
    public void changeState(SoldierState state){
        this.state = state;
        state.show();
    }
    public void transform(){
        state.transform(this);
    }
}

class SwordState extends SoldierState{
    private static SoldierState state = new SwordState();
    public static SoldierState getState(){
        return state;
    }
    public void show() {
        System.out.println("現在是步兵模式。");
    }
    public void transform(KnightContext knight) {
        changeState(knight, BowState.getState());
    }
}

class BowState extends SoldierState{
    private static SoldierState state = new BowState();
    public static SoldierState getState(){
        return state;
    }
    public void show() {
        System.out.println("現在是弓箭模式。");
    }
    public void transform(KnightContext knight) {
        changeState(knight, ShieldState.getState());
    }
}

class ShieldState extends SoldierState{
    private static SoldierState state = new ShieldState();
    public static SoldierState getState(){
        return state;
    }
    public void show() {
        System.out.println("現在是盾牌模式。");
    }
    public void transform(KnightContext knight) {
        changeState(knight, SwordState.getState());
    }
}

public class State
{
    public static void main(String[] args) {
        KnightContext knight = new KnightContext();
        knight.transform();
        knight.transform();
        knight.transform();
        knight.transform();
        knight.transform();
    }

  SwordState、BowState、ShieldState爲此兵種的三個狀態。KnightContext中有個SoldierState類型的成員state表示這個兵種的當前狀態。請注意,我們並不希望把如何切換的過程寫在KnightContext中(一般的想法可能是,在changeState中加入switch塊,這樣會使得KnightContext過於繁重),而是把如何轉換寫在了SoldierState的transform方法中。這樣就避免了在KnightContext中加入大量的切換狀態的代碼。如果需要新增加一個狀態,只需要修改和增加SoldierState的子類即可。對於每一個狀態,它都有一個單獨的子類來表示,因此在狀態多的情況下會出現很多個子類,這也是狀態模式的缺點。

  程序運行的結果爲:

現在是弓箭模式。

現在是盾牌模式。

現在是步兵模式。

現在是弓箭模式。

現在是盾牌模式。

  以上便是狀態模式的說明,希望能夠對大家有所幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章