前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >状态模式--黑崎一护的嗑药历程

状态模式--黑崎一护的嗑药历程

作者头像
zhanyd
发布2022-05-16 13:40:42
3870
发布2022-05-16 13:40:42
举报
文章被收录于专栏:编程我也会编程我也会

变身药丸

黑崎一护在和蓝染战斗中,使用了最后的月牙天冲重创蓝染,最终被被浦原喜助使用封印封锁。

一护立下大功,同时也丧失了死神的力量,无法使用战魂刀变身了。

十二番队长涅茧利为了感谢一户,苦心研发了能够暂时获得死神能力的三种药丸:

初解药丸

卍解药丸

虚化药丸

这三种药丸服用之后能够变身成相应的状态,同时拥有对应的必杀技,战斗力大大增强

黑崎一护的变身状态一览

正常状态

战斗力指数:100

始解状态

战斗力指数:200

卍解状态

战斗力指数:500

虚化状态

战斗力指数:1000

十二番队长涅茧利特意嘱咐了下用药规则,正常状态下只有吃始解药丸和卍解药丸才有作用。

虚化药丸只有在卍解状态下吃才有作用,还有,同一种药丸重复吃是没有用的,不要浪费哦。

另外,变身状态下,使用了必杀技之后,药效就会消失,立即恢复到正常状态,要注意哦,副队长涅音梦提醒道。

贴心的副队长涅音梦还画了幅状态转换图:

普通的实现方法

状态枚举类

代码语言:javascript
复制
public enum State {

    /**
     * 正常状态
     */
    NORMAL(0),
    /**
     * 始解状态
     */
    INITIAL(1),
    /**
     * 卍解状态
     */
    SWASTIKA(2),
    /**
     * 虚化状态
     */
    BLUR(3);

    private int value;

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

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

变身状态机类

代码语言:javascript
复制
public class TransformStateMachine {

    /**
     * 战斗力
     */
    private int fightingPower;
    /**
     * 当前状态
     */
    private State currentState;


    public int getFightingPower() {
        return this.fightingPower;
    }

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

    /**
     * 初始化
     */
    public TransformStateMachine() {
        this.fightingPower = 100;
        this.currentState = State.NORMAL;
    }

    /**
     * 吃下始解药丸
     */
    public void eateInitialPill() {
        System.out.println("吃下始解药丸");
        if(currentState.equals(State.NORMAL)) {
            this.currentState = State.INITIAL;
            this.fightingPower += 200;
            System.out.println("**变身始解状态**战斗力加200");
        } else {
            System.out.println("木有任何变化。。。");
        }
    }

    /**
     * 吃下卍解药丸
     */
    public void eateSwastikaPill() {
        System.out.println("吃下卍解药丸");
        if(currentState.equals(State.NORMAL) || currentState.equals(State.INITIAL)) {
            this.currentState = State.SWASTIKA;
            this.fightingPower += 500;
            System.out.println("**变身卍解状态**战斗力加500");
        } else {
            System.out.println("木有任何变化。。。");
        }
    }

    /**
     * 吃下虚化药丸
     */
    public void eateBlurPill() {
        System.out.println("吃下虚化药丸");
        if(currentState.equals(State.SWASTIKA)) {
            this.currentState = State.BLUR;
            this.fightingPower += 1000;
            System.out.println("**变身虚化状态**战斗力加1000");
        } else {
            System.out.println("木有任何变化。。。");
        }
    }

    /**
     * 使用必杀技
     */
    public void useUniqueSkill() {
        System.out.println("使用必杀技");
        if(currentState.equals(State.INITIAL) || currentState.equals(State.SWASTIKA) || currentState.equals(State.BLUR)) {
            System.out.println("月牙天冲--->");
            this.currentState = State.NORMAL;
            this.fightingPower = 100;
            System.out.println("**变回初始状态**战斗力变成100");
        } else {
            System.out.println("木有任何变化。。。");
        }
    }
}

测试类

代码语言:javascript
复制
public class Test {

    public static void main(String[] args) {
        TransformStateMachine transformStateMachine = new TransformStateMachine();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.eateInitialPill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.eateSwastikaPill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.eateBlurPill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.useUniqueSkill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.useUniqueSkill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
    }
}

运行结果

代码语言:javascript
复制
当前状态: NORMAL; 战斗力指数: 100

吃下始解药丸
**变身始解状态**战斗力加200
当前状态: INITIAL; 战斗力指数: 300

吃下卍解药丸
**变身卍解状态**战斗力加500
当前状态: SWASTIKA; 战斗力指数: 800

吃下虚化药丸
**变身虚化状态**战斗力加1000
当前状态: BLUR; 战斗力指数: 1800

使用必杀技
月牙天冲--->
**变回初始状态**战斗力变成100
当前状态: NORMAL; 战斗力指数: 100

使用必杀技
木有任何变化。。。
当前状态: NORMAL; 战斗力指数: 100

如果是简单的状态转换来说,这种方式是最简单直接的首选方法。

如果状态很多,这样编写的代码会包含大量的 if-else 或 switch-case 分支判断逻辑,可读性和可维护性都很差。

而且不符合开闭原则,如果修改了状态机中的某个状态转移,我们要在冗长的分支逻辑中找到对应的代码进行修改,很容易改错,引入 bug。

使用状态模式

我们要重构一下上面的代码,试着把每个状态的行为封装到一个类里,“封装了变化”,这样能让逻辑和结构更加清晰。

而且,我们针对某个状态的改变就不会影响其他的状态了,让修改和维护更容易。

这时候就要请状态模式出马了。

状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

本例的类图如下:

状态枚举类

代码语言:javascript
复制
public enum State {

    /**
     * 正常状态
     */
    NORMAL(0),
    /**
     * 始解状态
     */
    INITIAL(1),
    /**
     * 卍解状态
     */
    SWASTIKA(2),
    /**
     * 虚化状态
     */
    BLUR(3);

    private int value;

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

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

状态类接口

代码语言:javascript
复制
public interface ITransformState {

    /**
     * 获取当前状态
     * @return
     */
    State getState();

    /**
     * 吃下始解药丸
     */
    void eateInitialPill();

    /**
     * 吃下卍解药丸
     */
    void eateSwastikaPill();

    /**
     * 吃下虚化药丸
     */
    void eateBlurPill();

    /**
     * 使用必杀技
     */
    void useUniqueSkill();
}

初始状态实现类

代码语言:javascript
复制
public class NormalTransform implements ITransformState{

    private TransformStateMachine transformStateMachine;

    public NormalTransform(TransformStateMachine transformStateMachine) {
        this.transformStateMachine = transformStateMachine;
    }

    /**
     * 获取当前状态
     * @return
     */
    public State getState() {
        return State.NORMAL;
    }

    /**
     * 吃下始解药丸
     */
    public void eateInitialPill() {
        System.out.println("吃下始解药丸");
        transformStateMachine.setCurrentState(new InitialTransform(transformStateMachine));
        transformStateMachine.setFightingPower(transformStateMachine.getFightingPower() + 200);
        System.out.println("**变身始解状态**战斗力加200");
    }

    /**
     * 吃下卍解药丸
     */
    public void eateSwastikaPill() {
        System.out.println("吃下卍解药丸");
        transformStateMachine.setCurrentState(new SwastikaTransform(transformStateMachine));
        transformStateMachine.setFightingPower(transformStateMachine.getFightingPower() + 500);
        System.out.println("**变身卍解状态**战斗力加500");
    }

    /**
     * 吃下虚化药丸
     */
    public void eateBlurPill() {
        System.out.println("吃下虚化药丸");
        System.out.println("木有任何变化。。。");
    }

    /**
     * 使用必杀技
     */
    public void useUniqueSkill() {
        System.out.println("使用必杀技");
        System.out.println("木有任何变化。。。");
    }
}

始解状态实现类

代码语言:javascript
复制
public class InitialTransform implements ITransformState{

    private TransformStateMachine transformStateMachine;

    public InitialTransform(TransformStateMachine transformStateMachine) {
        this.transformStateMachine = transformStateMachine;
    }

    /**
     * 获取当前状态
     * @return
     */
    public State getState() {
        return State.INITIAL;
    }

    /**
     * 吃下始解药丸
     */
    public void eateInitialPill() {
        System.out.println("吃下始解药丸");
        System.out.println("木有任何变化。。。");
    }

    /**
     * 吃下卍解药丸
     */
    public void eateSwastikaPill() {
        System.out.println("吃下卍解药丸");
        transformStateMachine.setCurrentState(new SwastikaTransform(transformStateMachine));
        transformStateMachine.setFightingPower(transformStateMachine.getFightingPower() + 500);
        System.out.println("**变身卍解状态**战斗力加500");
    }

    /**
     * 吃下虚化药丸
     */
    public void eateBlurPill() {
        System.out.println("吃下虚化药丸");
        System.out.println("木有任何变化。。。");
    }

    /**
     * 使用必杀技
     */
    public void useUniqueSkill() {
        System.out.println("使用必杀技");
        System.out.println("月牙天冲--->");
        transformStateMachine.setCurrentState(new NormalTransform(transformStateMachine));
        transformStateMachine.setFightingPower(100);
        System.out.println("**变回初始状态**战斗力变成100");
    }
}

卍解状态实现类

代码语言:javascript
复制
public class SwastikaTransform implements ITransformState {

    private TransformStateMachine transformStateMachine;

    public SwastikaTransform(TransformStateMachine transformStateMachine) {
        this.transformStateMachine = transformStateMachine;
    }

    /**
     * 获取当前状态
     * @return
     */
    public State getState() {
        return State.SWASTIKA;
    }

    /**
     * 吃下始解药丸
     */
    public void eateInitialPill() {
        System.out.println("吃下始解药丸");
        System.out.println("木有任何变化。。。");
    }

    /**
     * 吃下卍解药丸
     */
    public void eateSwastikaPill() {
        System.out.println("吃下始解药丸");
        System.out.println("木有任何变化。。。");
    }

    /**
     * 吃下虚化药丸
     */
    public void eateBlurPill() {
        System.out.println("吃下虚化药丸");
        transformStateMachine.setCurrentState(new BlurTransform(transformStateMachine));
        transformStateMachine.setFightingPower(transformStateMachine.getFightingPower() + 1000);
        System.out.println("**变身虚化状态**战斗力加1000");
    }

    /**
     * 使用必杀技
     */
    public void useUniqueSkill() {
        System.out.println("使用必杀技");
        System.out.println("黑流牙突--->");
        transformStateMachine.setCurrentState(new NormalTransform(transformStateMachine));
        transformStateMachine.setFightingPower(100);
        System.out.println("**变回初始状态**战斗力变成100");
    }
}

虚化状态实现类

代码语言:javascript
复制
public class BlurTransform implements ITransformState {

    private TransformStateMachine transformStateMachine;

    public BlurTransform(TransformStateMachine transformStateMachine) {
        this.transformStateMachine = transformStateMachine;
    }

    /**
     * 获取当前状态
     * @return
     */
    public State getState() {
        return State.BLUR;
    }

    /**
     * 吃下始解药丸
     */
    public void eateInitialPill() {
        System.out.println("吃下始解药丸");
        System.out.println("木有任何变化。。。");
    }

    /**
     * 吃下卍解药丸
     */
    public void eateSwastikaPill() {
        System.out.println("吃下卍解药丸");
        System.out.println("木有任何变化。。。");
    }

    /**
     * 吃下虚化药丸
     */
    public void eateBlurPill() {
        System.out.println("吃下虚化药丸");
        System.out.println("木有任何变化。。。");
    }

    /**
     * 使用必杀技
     */
    public void useUniqueSkill() {
        System.out.println("使用必杀技");
        System.out.println("王虚的闪光--->");
        transformStateMachine.setCurrentState(new NormalTransform(transformStateMachine));
        transformStateMachine.setFightingPower(100);
        System.out.println("**变回初始状态**战斗力变成100");
    }
}

变身状态机类

代码语言:javascript
复制
public class TransformStateMachine {

    /**
     * 战斗力
     */
    private int fightingPower;
    /**
     * 当前状态
     */
    private ITransformState currentState;

    /**
     * 初始化
     */
    public TransformStateMachine() {
        this.fightingPower = 100;
        this.currentState = new NormalTransform(this);
    }

    /**
     * 吃下始解药丸
     */
    public void eateInitialPill() {
        this.currentState.eateInitialPill();
    }

    /**
     * 吃下卍解药丸
     */
    public void eateSwastikaPill() {
        this.currentState.eateSwastikaPill();
    }

    /**
     * 吃下虚化药丸
     */
    public void eateBlurPill() {
        this.currentState.eateBlurPill();
    }

    /**
     * 使用必杀技
     */
    public void useUniqueSkill() {
        this.currentState.useUniqueSkill();
    }

    public int getFightingPower() {
        return this.fightingPower;
    }

    public void setFightingPower(int fightingPower) {
        this.fightingPower = fightingPower;
    }

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

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

测试类

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        TransformStateMachine transformStateMachine = new TransformStateMachine();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.eateInitialPill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.eateBlurPill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.eateSwastikaPill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.eateBlurPill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.useUniqueSkill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.eateSwastikaPill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
        transformStateMachine.useUniqueSkill();
        System.out.println("当前状态: " + transformStateMachine.getCurrentState() + "; 战斗力指数: " + transformStateMachine.getFightingPower() + '\n');
    }
}

测试结果

代码语言:javascript
复制
当前状态: NORMAL; 战斗力指数: 100

吃下始解药丸
**变身始解状态**战斗力加200
当前状态: INITIAL; 战斗力指数: 300

吃下虚化药丸
木有任何变化。。。
当前状态: INITIAL; 战斗力指数: 300

吃下卍解药丸
**变身卍解状态**战斗力加500
当前状态: SWASTIKA; 战斗力指数: 800

吃下虚化药丸
**变身虚化状态**战斗力加1000
当前状态: BLUR; 战斗力指数: 1800

使用必杀技
王虚的闪光--->
**变回初始状态**战斗力变成100
当前状态: NORMAL; 战斗力指数: 100

吃下卍解药丸
**变身卍解状态**战斗力加500
当前状态: SWASTIKA; 战斗力指数: 600

使用必杀技
黑流牙突--->
**变回初始状态**战斗力变成100
当前状态: NORMAL; 战斗力指数: 100

总结

状态模式一般用来实现有限状态机。

有限状态机的英文翻译是 Finite State Machine,缩写为 FSM,简称为状态机。

状态机有 3 个组成部分:状态(State)、事件(Event)、动作(Action)。其中,事件也称为转移条件(Transition Condition)。事件触发状态的转移及动作的执行。

不过,动作不是必须的,也可能只转移状态,不执行任何动作。

状态机的状态随着某种事件的发生而改变,事件就是状态转移的条件,状态转移时可能会有相应的操作要同时进行。

状态模式的优点:

1.如果状态变更伴随着复杂的操作,状态模式能把所有操作封装到一个类里,允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。

2.把每个状态和动作提取出来,封装到一个类中,就把着眼点从执行状态提高到整个对象的状态,这将使代码更加结构化,整体意图更加清晰。

3.以后对状态的修改之需要修改一个子类,新增一个新的状态,只需要新增一个状态类,对原有代码的修改少。

状态模式的缺点:

1.会增加系统类和对象的个数。

2.一个State的子类至少拥有一个其他子类的信息,各个子类之间产生了依赖。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-06-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程我也会 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 变身药丸
  • 黑崎一护的变身状态一览
    • 正常状态
      • 始解状态
        • 卍解状态
          • 虚化状态
            • 状态模式的优点:
            • 状态模式的缺点:
        • 普通的实现方法
        • 使用状态模式
        • 总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档