变身药丸
黑崎一护在和蓝染战斗中,使用了最后的月牙天冲重创蓝染,最终被被浦原喜助使用封印封锁。
一护立下大功,同时也丧失了死神的力量,无法使用斩魂刀变身了。
十二番队长涅茧利为了感谢一户,苦心研发了能够暂时获得死神能力的三种药丸:初解药丸,卍解药丸和虚化药丸。
这三种药丸服用之后能够变身成相应的状态,同时拥有对应的必杀技,战斗力大大增强。
黑崎一护的变身状态一览
正常状态
战斗力指数: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的子类至少拥有一个其他子类的信息,各个子类之间产生了依赖。