ITPub博客

首页 > 数据库 > 数据库开发技术 > 状态模式--黑崎一护的嗑药历程

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

原创 数据库开发技术 作者:zhanyd 时间:2020-06-20 21:13:14 0 删除 编辑


变身药丸

黑崎一护在和蓝染战斗中,使用了最后的月牙天冲重创蓝染,最终被被浦原喜助使用封印封锁。
一护立下大功,同时也丧失了死神的力量,无法使用战魂刀变身了。
十二番队长涅茧利为了感谢一户,苦心研发了能够暂时获得死神能力的三种药丸:
初解药丸
卍解药丸
虚化药丸
这三种药丸服用之后能够变身成相应的状态,同时拥有对应的必杀技,战斗力大大增强。


黑崎一护的变身状态一览

正常状态

战斗力指数:100


始解状态

战斗力指数:200


卍解状态

战斗力指数:500

虚化状态

战斗力指数:1000


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

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

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

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


普通的实现方法

状态枚举类
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;
}
}
变身状态机类
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("木有任何变化。。。");
}
}
}
测试类
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');
}
}
运行结果
当前状态: NORMAL; 战斗力指数: 100

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

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

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

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

使用必杀技
木有任何变化。。。
当前状态: NORMAL; 战斗力指数: 100
如果是简单的状态转换来说,这种方式是最简单直接的首选方法。
如果状态很多,这样编写的代码会包含大量的 if-else 或 switch-case 分支判断逻辑,可读性和可维护性都很差。
而且不符合开闭原则,如果修改了状态机中的某个状态转移,我们要在冗长的分支逻辑中找到对应的代码进行修改,很容易改错,引入 bug。


使用状态模式

我们要重构一下上面的代码,试着把每个状态的行为封装到一个类里,“封装了变化”,这样能让逻辑和结构更加清晰。
而且,我们针对某个状态的改变就不会影响其他的状态了,让修改和维护更容易。
这时候就要请状态模式出马了。
状态模式(State Pattern) :允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。


本例的类图如下:

状态枚举类
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;
}
}
状态类接口
public interface ITransformState {

/**
* 获取当前状态
* @return
*/

State getState();

/**
* 吃下始解药丸
*/

void eateInitialPill();

/**
* 吃下卍解药丸
*/

void eateSwastikaPill();

/**
* 吃下虚化药丸
*/

void eateBlurPill();

/**
* 使用必杀技
*/

void useUniqueSkill();
}
初始状态实现类
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("木有任何变化。。。");
}
}
始解状态实现类
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");
}
}
卍解状态实现类
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");
}
}
虚化状态实现类
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");
}
}
变身状态机类
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;
}
}
测试类
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');
}
}
测试结果
当前状态: 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的子类至少拥有一个其他子类的信息,各个子类之间产生了依赖。
(公众号回复:设计模式代码,获取git代码链接)






原文作者:编程我也会;如有侵权,请联系管理员删除。

上一篇: centos7 NFS 配置
请登录后发表评论 登录
全部评论

注册时间:2018-06-20

  • 博文量
    120
  • 访问量
    51697