Java设计模式及应用场景之《状态模式》

一、状态模式定义

Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.
(允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。)

二、状态模式的结构和说明

在这里插入图片描述

  • Context 环境,也称上下文。 定义客户端需要的接口,并且负责具体状态的切换。
  • State 状态接口。 负责状态行为方法的声明定义。
  • ConcreteState 具体实现状态处理的类。 实现State状态接口中声明的方法。

三、状态模式示例

  玩《王者农药》的同学都知道,王者中很多英雄是支持多形态的,以裴擒虎为例,裴擒虎在人形态和虎形态状态下,普通攻击以及各个技能效果都是不同的。
  我们通过代码来模拟一下。

不用状态模式的实现方式

定义裴擒虎类,类中记录当前所属形态,通过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逻辑,这样就方便多了。

四、状态模式的优缺点

优点:

  • 简化应用逻辑控制。 使用单独的类来封装一个状态的处理,使得代码结构和意图更清晰。减少if-else,避免出现巨大的条件语句。
  • 更好的扩展性。 扩展新状态时,只需要新增加一个状态实现类,然后在状态维护或切换的地方简单处理一下即可。
  • 显示化进行状态转换。 状态模式为不同的状态引入独立的对象,使得状态的转换变得更加明确。

缺点:

  • 一个状态一个处理类,如果状态太多,会增加很多类对象。
  • 状态模式对"开闭原则"的支持并不完美,当增加新的状态类时,还是需要修改那些负责状态转换的源代码逻辑。

五、状态模式的应用场景及案例

  • 行为随状态改变而改变的场景。
  • 条件、分支判断语句的替代者。
  • 工作流的设计。
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晓呆同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值