十五、状态模式
本文最后更新于 985 天前,其中的信息可能已经有所发展或是发生改变。

State Pattern

有限状态机

简称状态机, 由三部分组成:状态、事件、动作。事件触发状态转移,执行动作(非必须)。

状态机实现方式一:分支逻辑法

就是各种if elseswitch case。判断不同的状态,遇到不同的事件,执行不同的操作,例如改变状态,执行动作。适用于简单的场景,毕竟不要过度设计。

状态机实现方式二:查表法

状态机有两个自变量(状态、事件)和一个因变量(动作)组成,如果动作简单,就可以将动作放入二维数组,通过状态和事件快速找出动作。另外可放入配置文件,不用硬编码,更加灵活。

状态转移的二维数组

马里奥的状态

private static final State[][] transitionTable = {                  
    {SUPER, CAPE, FIRE, SMALL},          
    {SUPER, CAPE, FIRE, SMALL},          
    {CAPE, CAPE, CAPE, SMALL},          
    {FIRE, FIRE, FIRE, SMALL}  
};

执行动作的二维数组

马里奥的分数

private static final int[][] actionTable = {          
    {+100, +200, +300, +0},          
    {+0, +200, +300, -100},          
    {+0, +0, +0, -200},          
    {+0, +0, +0, -300}  
};

状态机实现方式三:状态模式

如果动作复杂,查表就不太适用了。这时可以将事件抽取为接口,不同的状态实现各自需要的事件接口,执行相应的动作。

State:状态枚举类

public enum State {

    SMALL(0),
    SUPPER(1),
    FIRE(2);

    private int value;
}

事件

MeetMonster:遇到怪物
public interface MeetMonster extends Event{
    void meetMonster(MarioStateMachine marioStateMachine);
}
ObtainCape:获得蘑菇
public interface ObtainCape extends Event {
    void obtainCape(MarioStateMachine marioStateMachine);
}
ObtainFireFlower:获得火焰花
public interface ObtainFireFlower extends Event{
    void obtainFireFlower(MarioStateMachine marioStateMachine);
}

状态

Mario:马里奥状态抽象类

为了让状态类只实现各自所需的接口,并且状态机可以不区分状态类,执行所有动作。需要在事件接口和状态实现类之间添加一层抽象类,实现所有事件,状态子类只需重写自己需要实现的事件方法。

public abstract class Mario implements ObtainCape, ObtainFireFlower, MeetMonster {
    public abstract State getState();

    public void obtainCapeWrapper(MarioStateMachine marioStateMachine) {
        System.out.print(" 获得蘑菇 ");
        obtainCape(marioStateMachine);
    }

    @Override
    public void obtainCape(MarioStateMachine marioStateMachine) {
        throw new RuntimeException("unimplemented exception");
    }

    public void obtainFireFlowerWrapper(MarioStateMachine marioStateMachine) {
        System.out.print(" 获得火焰花 ");
        obtainFireFlower(marioStateMachine);
    }

    @Override
    public void obtainFireFlower(MarioStateMachine marioStateMachine) {
        throw new RuntimeException("unimplemented exception");
    }

    public void meetMonsterWrapper(MarioStateMachine marioStateMachine) {
        System.out.print(" 遇到怪物 ");
        meetMonster(marioStateMachine);
    }

    @Override
    public void meetMonster(MarioStateMachine marioStateMachine) {
        if (marioStateMachine.getCurrentSate().getState().equals(State.SMALL)) {
            System.out.print(" 嗝屁 ");
        } else {
            System.out.print(" 变小 ");
            marioStateMachine.setCurrentSate(SmallMario.getInstance());
        }
        System.out.print(" 分数减100 \n");
        marioStateMachine.setScore(marioStateMachine.getScore()-100);
    }
}
FireMario:火焰马里奥状态
public class FireMario extends Mario {
    public static final FireMario instance=new FireMario();

    public static FireMario getInstance() {
        return instance;
    }

    private FireMario() {

    }

    @Override
    public State getState() {
        return State.FIRE;
    }

    @Override
    public void obtainCape(MarioStateMachine marioStateMachine) {
        System.out.print(" 变大 ");
        marioStateMachine.setCurrentSate(SupperMario.getInstance());
        System.out.print(" 分数加300 \n");
        marioStateMachine.setScore(marioStateMachine.getScore()+300);
    }

    @Override
    public void obtainFireFlower(MarioStateMachine marioStateMachine) {
        System.out.print(" 分数加200 \n");
        marioStateMachine.setScore(marioStateMachine.getScore()+200);
    }
}
SmallMario:小的马里奥状态
public class SmallMario extends Mario{

    public static final SmallMario instance=new SmallMario();

    public static SmallMario getInstance() {
        return instance;
    }

    private SmallMario() {

    }

    @Override
    public State getState() {
        return State.SMALL;
    }

    @Override
    public void obtainCape(MarioStateMachine marioStateMachine) {
        System.out.print(" 变大 ");
        marioStateMachine.setCurrentSate(SupperMario.getInstance());
        System.out.print(" 分数加100 \n");
        marioStateMachine.setScore(marioStateMachine.getScore()+100);
    }

    @Override
    public void obtainFireFlower(MarioStateMachine marioStateMachine) {
        System.out.print(" 变火人 ");
        marioStateMachine.setCurrentSate(FireMario.getInstance());
        System.out.print(" 分数加200 \n");
        marioStateMachine.setScore(marioStateMachine.getScore()+200);
    }
}
SupperMario:超级马里奥状态
public class SupperMario extends Mario {

    public static final SupperMario instance=new SupperMario();

    public static SupperMario getInstance() {
        return instance;
    }

    private SupperMario() {

    }

    @Override
    public State getState() {
        return State.SUPPER;
    }

    @Override
    public void obtainCape(MarioStateMachine marioStateMachine) {
        System.out.print(" 分数加200 \n");
        marioStateMachine.setScore(marioStateMachine.getScore()+200);
    }

    @Override
    public void obtainFireFlower(MarioStateMachine marioStateMachine) {
        System.out.print(" 变火人 ");
        marioStateMachine.setCurrentSate(FireMario.getInstance());
        System.out.print(" 分数加300 \n");
        marioStateMachine.setScore(marioStateMachine.getScore()+300);
    }
}

MarioStateMachine:状态机

public class MarioStateMachine {

    private int score;
    private Mario currentSate;

    public MarioStateMachine() {
        System.out.print(" 初始化马里奥,分数为0,状态为small \n");
        score = 0;
        currentSate = SmallMario.getInstance();
    }

    public void obtainCape() {
        this.currentSate.obtainCapeWrapper(this);
    }

    public void meetMonster() {
        this.currentSate.meetMonsterWrapper(this);
    }

    public void obtainFireFlower() {
        this.currentSate.obtainFireFlowerWrapper(this);
    }
}

Application:应用类

public class Application {
    public static void main(String[] args) {
        MarioStateMachine marioStateMachine = new MarioStateMachine();
        marioStateMachine.obtainCape();
        marioStateMachine.obtainCape();
        marioStateMachine.obtainFireFlower();
        marioStateMachine.meetMonster();
        marioStateMachine.obtainFireFlower();
        marioStateMachine.obtainCape();
        marioStateMachine.obtainCape();
        marioStateMachine.obtainFireFlower();
        System.out.println("最终成绩:"+marioStateMachine.getScore());
    }
}

输出结果

 初始化马里奥,分数为0,状态为small 
 获得蘑菇  变大  分数加100 
 获得蘑菇  分数加200 
 获得火焰花  变火人  分数加300 
 遇到怪物  变小  分数减100 
 获得火焰花  变火人  分数加200 
 获得蘑菇  变大  分数加300 
 获得蘑菇  分数加200 
 获得火焰花  变火人  分数加300 
 最终成绩:1500

总结

状态模式是有限状态机的一种实现,适合状态不多(类爆炸),动作复杂的场景。

状态多,动作简单适合查表法。

状态不多,动作也简单适合分支逻辑法。

作者:Yuyy
博客:https://yuyy.info
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇