Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.
(允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。)
玩《王者农药》的同学都知道,王者中很多英雄是支持多形态的,以裴擒虎为例,裴擒虎在人形态和虎形态状态下,普通攻击以及各个技能效果都是不同的。
我们通过代码来模拟一下。
不用状态模式的实现方式
定义裴擒虎类,类中记录当前所属形态,通过if-else区分不同形态进行不同的逻辑处理。
/**
* 裴擒虎
*/
public class Peiqianhu {
/**
* 定义裴擒虎形态枚举
*/
enum PeiqianhuShapeState{
HUMAN, TIGER}
/**
* 裴擒虎当前形态
*/
private PeiqianhuShapeState peiqianhuShapeState;
/**
* 更换形态
*/
public void changeState(PeiqianhuShapeState peiqianhuShapeState){
this.peiqianhuShapeState = peiqianhuShapeState;
}
/**
* 普通攻击
*/
public void normalAttack() {
if(Objects.equals(peiqianhuShapeState, PeiqianhuShapeState.HUMAN)){
System.out.println("【人形态 - 普攻】远程气波攻击");
}else if(Objects.equals(peiqianhuShapeState, PeiqianhuShapeState.TIGER)){
System.out.println("【虎形态 - 普攻】近距离爪击攻击");
}else{
System.out.println("不支持的形态");
}
}
/**
* 释放一技能
*/
public void releaseFirstSkill() {
if(Objects.equals(peiqianhuShapeState, PeiqianhuShapeState.HUMAN)){
System.out.println("【人形态 - 一技能 - 冲拳式】朝指定方向发出气功波");
}else if(Objects.equals(peiqianhuShapeState, PeiqianhuShapeState.TIGER)){
System.out.println("【虎形态 - 一技能 - 虎啸式】对一名敌人发起撕咬");
}else{
System.out.println("不支持的形态");
}
}
/**
* 释放二技能
*/
public void releaseSecondSkill() {
if(Objects.equals(peiqianhuShapeState, PeiqianhuShapeState.HUMAN)){
System.out.println("【人形态 - 二技能 - 气守式】施展念气,产生护盾");
}else if(Objects.equals(peiqianhuShapeState, PeiqianhuShapeState.TIGER)){
System.out.println("【虎形态 - 二技能 - 虎跃式】朝指定方向冲刺");
}else{
System.out.println("不支持的形态");
}
}
/**
* 释放三技能
*/
public void releaseThirdSkill() {
if(Objects.equals(peiqianhuShapeState, PeiqianhuShapeState.HUMAN)){
System.out.println("【人形态 - 三技能 - 虎啸风生】变身为虎形态");
// 变身为虎形态
changeState(PeiqianhuShapeState.TIGER);
}else if(Objects.equals(peiqianhuShapeState, PeiqianhuShapeState.TIGER)){
System.out.println("【虎形态 - 三技能 - 形意六合】变身为人形态");
// 变身为人形态
changeState(PeiqianhuShapeState.HUMAN);
}else{
System.out.println("不支持的形态");
}
}
}
通过客户端来模拟一下效果
public static void main(String[] args) {
Peiqianhu peiqianhu = new Peiqianhu();
// 开始形态为人形态
peiqianhu.changeState(Peiqianhu.PeiqianhuShapeState.HUMAN);
// 普通攻击
peiqianhu.normalAttack();
// 释放一技能
peiqianhu.releaseFirstSkill();
// 释放二技能
peiqianhu.releaseSecondSkill();
// 释放三技能(变身)
peiqianhu.releaseThirdSkill();
// 普通攻击
peiqianhu.normalAttack();
// 释放一技能
peiqianhu.releaseFirstSkill();
// 释放二技能
peiqianhu.releaseSecondSkill();
// 释放三技能(变身)
peiqianhu.releaseThirdSkill();
// 普通攻击
peiqianhu.normalAttack();
}
运行后输出如下:
【人形态 - 普攻】远程气波攻击
【人形态 - 一技能 - 冲拳式】朝指定方向发出气功波
【人形态 - 二技能 - 气守式】施展念气,产生护盾
【人形态 - 三技能 - 虎啸风生】变身为虎形态
【虎形态 - 普攻】近距离爪击攻击
【虎形态 - 一技能 - 虎啸式】对一名敌人发起撕咬
【虎形态 - 二技能 - 虎跃式】朝指定方向冲刺
【虎形态 - 三技能 - 形意六合】变身为人形态
【人形态 - 普攻】远程气波攻击
看起来还是挺简单的,但是,用这种方式实现会存在一个问题,如果裴擒虎增加一个新形态,比如猫形态,就需要在各个方法中修改if-else结构,这样会非常的不方便。
再来看下通过状态模式的实现方式
定义抽象状态类,声明每种形态下裴擒虎的操作。
/**
* 封装裴擒虎不同形态下的操作内容
*/
public abstract class PeiqianhuShapeState {
protected Peiqianhu peiqianhu;
public void setPeiqianhu(Peiqianhu peiqianhu) {
this.peiqianhu = peiqianhu;
}
/**
* 普通攻击
*/
abstract void normalAttack();
/**
* 释放一技能
*/
abstract void releaseFirstSkill();
/**
* 释放二技能
*/
abstract void releaseSecondSkill();
/**
* 释放三技能(大招)
*/
abstract void releaseThirdSkill();
}
人形态的实现类
/**
* 裴擒虎人形态
*/
public class PeiqianhuHumanShapeState extends PeiqianhuShapeState{
@Override
public void normalAttack() {
System.out.println("【人形态 - 普攻】远程气波攻击");
}
@Override
public void releaseFirstSkill() {
System.out.println("【人形态 - 一技能 - 冲拳式】朝指定方向发出气功波");
}
@Override
public void releaseSecondSkill() {
System.out.println("【人形态 - 二技能 - 气守式】施展念气,产生护盾");
}
@Override
public void releaseThirdSkill() {
System.out.println("【人形态 - 三技能 - 虎啸风生】变身为虎形态");
super.peiqianhu.changeState(new PeiqianhuTigerShapeState());
}
}
虎形态的实现类
/**
* 裴擒虎虎形态
*/
public class PeiqianhuTigerShapeState extends PeiqianhuShapeState{
@Override
public void normalAttack() {
System.out.println("【虎形态 - 普攻】近距离爪击攻击");
}
@Override
public void releaseFirstSkill() {
System.out.println("【虎形态 - 一技能 - 虎啸式】对一名敌人发起撕咬");
}
@Override
public void releaseSecondSkill() {
System.out.println("【虎形态 - 二技能 - 虎跃式】朝指定方向冲刺");
}
@Override
public void releaseThirdSkill() {
System.out.println("【虎形态 - 三技能 - 形意六合】变身为人形态");
super.peiqianhu.changeState(new PeiqianhuHumanShapeState());
}
}
定义裴擒虎类,类中持有当前所属的形态,并且可以切换形态
/**
* 裴擒虎
*/
public class Peiqianhu {
/**
* 裴擒虎当前形态
*/
private PeiqianhuShapeState peiqianhuShapeState;
/**
* 更换形态
*/
public void changeState(PeiqianhuShapeState peiqianhuShapeState){
this.peiqianhuShapeState = peiqianhuShapeState;
// 通知到实现类中去
this.peiqianhuShapeState.setPeiqianhu(this);
}
/**
* 普通攻击
*/
public void normalAttack() {
peiqianhuShapeState.normalAttack();
}
/**
* 释放一技能
*/
public void releaseFirstSkill() {
peiqianhuShapeState.releaseFirstSkill();
}
/**
* 释放二技能
*/
public void releaseSecondSkill() {
peiqianhuShapeState.releaseSecondSkill();
}
/**
* 释放三技能
*/
public void releaseThirdSkill() {
peiqianhuShapeState.releaseThirdSkill();
}
}
再来通过客户端来模拟一下效果
public static void main(String[] args) {
Peiqianhu peiqianhu = new Peiqianhu();
// 开始形态为人形态
peiqianhu.changeState(new PeiqianhuHumanShapeState());
// 普通攻击
peiqianhu.normalAttack();
// 释放一技能
peiqianhu.releaseFirstSkill();
// 释放二技能
peiqianhu.releaseSecondSkill();
// 释放三技能(变身)
peiqianhu.releaseThirdSkill();
// 普通攻击
peiqianhu.normalAttack();
// 释放一技能
peiqianhu.releaseFirstSkill();
// 释放二技能
peiqianhu.releaseSecondSkill();
// 释放三技能(变身)
peiqianhu.releaseThirdSkill();
// 普通攻击
peiqianhu.normalAttack();
}
运行后输出如下:
【人形态 - 普攻】远程气波攻击
【人形态 - 一技能 - 冲拳式】朝指定方向发出气功波
【人形态 - 二技能 - 气守式】施展念气,产生护盾
【人形态 - 三技能 - 虎啸风生】变身为虎形态
【虎形态 - 普攻】近距离爪击攻击
【虎形态 - 一技能 - 虎啸式】对一名敌人发起撕咬
【虎形态 - 二技能 - 虎跃式】朝指定方向冲刺
【虎形态 - 三技能 - 形意六合】变身为人形态
【人形态 - 普攻】远程气波攻击
通过输出可以看出,使用状态模式和不使用模式,都可以达到相同的效果。
但如果使用状态模式的情况下,再新增加一种形态,如猫形态,我们可以新定义一个猫形态的状态类,然后简单修改下释放三技能变身那块的逻辑,不用每个方法都修改if-else逻辑,这样就方便多了。
优点:
缺点: