ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java设计模式之状态模式

2022-01-31 16:34:30  阅读:141  来源: 互联网

标签:java stateMachine void 模式 Override 设计模式 public currentState MarioStateMachine


在实际的软件开发中,状态模式不是很常用,但在一些能够用到的场景里,能发挥非常大的作用。

状态模式一般用于实现状态机,而状态机一般用在游戏、工作流引擎等软件开发中。

状态机有三个组成部分:状态、事件和动作。触发某个事件可以改变对象的状态。

以超级马里奥这个小游戏为例,一进入游戏是个小马里奥,吃到蘑菇就会变成超级马里奥,并增加相应积分,碰到怪兽又会变回小马里奥。减去积分。

获得火焰会变成火焰马里奥,获得斗篷会变成斗篷马里奥。

吃蘑菇等就是事件,小马里奥、超级马里奥、火焰马里奥就是状态,增加减少积分就是动作。

当状态转换逻辑比较简单的时候,完全可以在一个类中通过if/else把这些逻辑描述出来。

但当游戏很复杂,状态很多的时候,上面的代码的可读性和可维护性就会变得很差。这个时候就需要引入状态模式。

一、状态和事件

首先,我们通过一个枚举类存储所有状态

public enum State {
    SMALL(0),
    SUPER(1),
    FIRE(2),
    CAPE(3);

    private int value;

    private State(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }
}

然后定义一个马里奥接口,用来表示马里奥的所有事件

/**
 * 状态的接口,定义了所有事件,它的4个子类定义了状态机的所有状态
 */
public interface IMario {
    State getName();

    void obtainMushRoom(MarioStateMachine stateMachine);//吃到蘑菇

    void obtainCape(MarioStateMachine stateMachine);//获得斗篷

    void obtainFireFlower(MarioStateMachine stateMachine);//获得火焰

    void meetMonster(MarioStateMachine stateMachine);//遇到怪物
}

二、状态机类

状态机类存储了马里奥的当前积分和状态,是核心逻辑类,但因为我们应用了状态模式。所以具体每个状态的逻辑都被分配到具体的状态类中。

这样状态机类就会变得很轻量小巧。

/**
 * 原来的状态逻辑都集中在本类,采用if/else分支逻辑比较复杂,现在已经分散到四个状态类中
 * 状态机类和四个状态类是双向依赖关系,状态变化的逻辑通过调用状态子类完成实现
 */
public class MarioStateMachine {
    private int score;
    private IMario currentState;

    public MarioStateMachine() {
        this.score = 0;
        this.currentState = SmallMario.getInstance();
    }

    public void obtainMushRoom() {
        this.currentState.obtainMushRoom(this);
    }

    public void obtainCape() {
        this.currentState.obtainCape(this);
    }

    public void obtainFireFlower() {
        this.currentState.obtainFireFlower(this);
    }

    public void meetMonster() {
        this.currentState.meetMonster(this);
    }

    public int getScore() {
        return this.score;
    }

    public State getCurrentState() {
        return this.currentState.getName();
    }

    public void setScore(int score) {
        this.score = score;
    }

    public void setCurrentState(IMario currentState) { this.currentState = currentState; }
}

三、具体状态机类

在状态机中状态是不断切换的,但每个状态本身并不变化,所以我们将每个状态子类设计为单例类。

3.1.小马里奥

/**
 * 状态机是不断变化的,但状态子类本身是不变的,也没有成员变量,所有设置成单例更为合适
 * 设置成单例之后,状态子类就不能在持有状态机变量,但又要对状态机进行修改,可以把状态机作为状态转化的参数
 */
public class SmallMario implements IMario {
    private static final SmallMario instance = new SmallMario();

    private SmallMario() {
    }

    public static SmallMario getInstance() {
        return instance;
    }

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

    @Override
    public void obtainMushRoom(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(SuperMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() + 100);
    }

    @Override
    public void obtainCape(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(CapeMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() + 200);
    }

    @Override
    public void obtainFireFlower(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(FireMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() + 300);
    }

    @Override
    public void meetMonster(MarioStateMachine stateMachine) { // do nothing... }
    }

}

 

3.2.超级马里奥

public class SuperMario implements IMario {
    private static final SuperMario instance = new SuperMario();

    private SuperMario() {
    }

    public static SuperMario getInstance() {
        return instance;
    }

    @Override
    public State getName() {
        return State.SUPER;
    }

    @Override
    public void obtainMushRoom(MarioStateMachine stateMachine) {

    }

    @Override
    public void obtainCape(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(CapeMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() + 200);

    }

    @Override
    public void obtainFireFlower(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(FireMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() + 300);
    }

    @Override
    public void meetMonster(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(SmallMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() - 100);
    }
}

 

3.3.火焰马里奥

public class FireMario implements IMario {
    private static final FireMario instance = new FireMario();

    private FireMario() {
    }

    public static FireMario getInstance() {
        return instance;
    }

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

    @Override
    public void obtainMushRoom(MarioStateMachine stateMachine) {

    }

    @Override
    public void obtainCape(MarioStateMachine stateMachine) {

    }

    @Override
    public void obtainFireFlower(MarioStateMachine stateMachine) {

    }

    @Override
    public void meetMonster(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(SmallMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() - 300);
    }
}

 

3.4.斗篷马里奥

public class CapeMario implements IMario {
    private static final CapeMario instance = new CapeMario();

    private CapeMario() {
    }

    public static CapeMario getInstance() {
        return instance;
    }

    @Override
    public State getName() {
        return State.CAPE;
    }

    @Override
    public void obtainMushRoom(MarioStateMachine stateMachine) {

    }

    @Override
    public void obtainCape(MarioStateMachine stateMachine) {

    }

    @Override
    public void obtainFireFlower(MarioStateMachine stateMachine) {

    }

    @Override
    public void meetMonster(MarioStateMachine stateMachine) {
        stateMachine.setCurrentState(SmallMario.getInstance());
        stateMachine.setScore(stateMachine.getScore() - 200);
    }
}

 

四、开始游戏

这样设计,即便是以后再添加新的动作或状态,我们只需要添加新的状态类和方法,而不需要改变原因代码。

真正实现了对扩展开放,都修改关闭。

public class Application {
    public static void main(String[] args) {
        //初始化
        System.out.println("===========游戏开始===========");
        MarioStateMachine mario = new MarioStateMachine();
        State currentState = mario.getCurrentState();
        System.out.println(mario.getScore());
        System.out.println(currentState);
        //吃蘑菇
        System.out.println("===========吃蘑菇===========");
        mario.obtainMushRoom();
        currentState = mario.getCurrentState();
        System.out.println(mario.getScore());
        System.out.println(currentState);
        //获得斗篷
        System.out.println("============获得斗篷==========");
        mario.obtainCape();
        currentState = mario.getCurrentState();
        System.out.println(mario.getScore());
        System.out.println(currentState);

        //遇到怪物
        System.out.println("===========遇到怪物===========");
        mario.meetMonster();
        currentState = mario.getCurrentState();
        System.out.println(mario.getScore());
        System.out.println(currentState);

        //获得火焰
        System.out.println("============获得火焰==========");
        mario.obtainFireFlower();
        currentState = mario.getCurrentState();
        System.out.println(mario.getScore());
        System.out.println(currentState);
    }
}

输出:

===========游戏开始===========
SMALL
0
===========吃蘑菇===========
SUPER
100
============获得斗篷==========
CAPE
300
===========遇到怪物===========
SMALL
100
============获得火焰==========
FIRE
400

 

标签:java,stateMachine,void,模式,Override,设计模式,public,currentState,MarioStateMachine
来源: https://www.cnblogs.com/wangbin2188/p/15858353.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有