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

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的子類即可。對於每一個狀態,它都有一個單獨的子類來表示,因此在狀態多的情況下會出現很多個子類,這也是狀態模式的缺點。

  程式執行的結果為:

現在是弓箭模式。

現在是盾牌模式。

現在是步兵模式。

現在是弓箭模式。

現在是盾牌模式。

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