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的子类即可。对于每一个状态,它都有一个单独的子类来表示,因此在状态多的情况下会出现很多个子类,这也是状态模式的缺点。

  程序运行的结果为:

现在是弓箭模式。

现在是盾牌模式。

现在是步兵模式。

现在是弓箭模式。

现在是盾牌模式。

  以上便是状态模式的说明,希望能够对大家有所帮助。