前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >学习设计模式——状态模式

学习设计模式——状态模式

作者头像
玖柒的小窝
修改2021-11-08 09:35:57
8190
修改2021-11-08 09:35:57
举报
文章被收录于专栏:各类技术文章~

概述

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

状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

何时使用:

  • 状态模式一般用来实现状态机,而状态机常用在游戏、工作流引擎等系统开发中。
  • 代码中包含大量与对象状态有关的条件语句。

什么是状态机?

  • 状态机有 3 个组成部分:状态(State)、事件(Event)、动作(Action)。其中,事件也称为转移条件(Transition Condition)。事件触发状态的转移及动作的执行。不过,动作不是必须的,也可能只转移状态,不执行任何动作。

UML 类图:

image.png
image.png

角色组成:

  1. 上下文环境(Context):它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处理。
  2. 抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。
  3. 具体状态(Concrete State):实现抽象状态定义的接口。

通用代码

Context.java

代码语言:javascript
复制
public class Context {
    private State state;

    public Context() {
        this.state = new ConcreteStateA();  // 设置初始状态
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public void request() {
        this.state.handle(this);
    }

}
复制代码

State.java

代码语言:javascript
复制
public abstract class State {

    public abstract void handle(Context context);

}
复制代码

ConcreteStateA.java、ConcreteStateB.java

代码语言:javascript
复制
public class ConcreteStateA extends State {

    @Override
    public void handle(Context context) {
        System.out.println("ConcreteStateA 状态的 handle 方法");
        context.setState(this);
    }
}


public class ConcreteStateB extends State {

    @Override
    public void handle(Context context) {
        System.out.println("ConcreteStateB 状态的 handle 方法");
        context.setState(this);
    }
}
复制代码

测试:

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {

        Context context = new Context();
        context.request();
        System.out.println("当前状态为:" + context.getState());

        context.setState(new ConcreteStateB());
        context.request();
        System.out.println("当前状态为:" + context.getState());

    }
}
复制代码

结果:

ConcreteStateA 状态的 handle 方法 当前状态为:通用模板.ConcreteStateA@1b6d3586 ConcreteStateB 状态的 handle 方法 当前状态为:通用模板.ConcreteStateB@4554617c

具体实例

相信很多人都玩过王者荣耀这款手游,在对局中,王者荣耀里面的英雄遭受到不同的技能或者增益buff会有不同的状态,比如眩晕、加速、减速等等。如果不使用状态模式的话,我们的英雄类会非常的复杂和难以维护。此时使用状态模式才是更好的选择,下面用代码模拟实现一遍。

RunState.java

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

    void run(Hero hero);

}
复制代码

CommonState.java、SpeedUpState.java、SpeedDownState.java、SwimState.java

代码语言:javascript
复制
public class CommonState implements RunState {
    @Override
    public void run(Hero hero) {
        // 正常跑动
    }
}


public class SpeedUpState implements RunState {
    @Override
    public void run(Hero hero) {
        System.out.println("--------------加速跑动---------------");
        try {
            Thread.sleep(4000);//假设加速持续4秒
        } catch (InterruptedException e) {}
        hero.setState(Hero.COMMON);
        System.out.println("------加速状态结束,变为正常状态------");

    }
}


public class SpeedDownState implements RunState{
    @Override
    public void run(Hero hero) {
        System.out.println("--------------减速跑动---------------");
        try {
            Thread.sleep(4000);//假设减速持续4秒
        } catch (InterruptedException e) {}
        hero.setState(Hero.COMMON);
        System.out.println("------减速状态结束,变为正常状态------");
    }
}


public class SwimState implements RunState{
    @Override
    public void run(Hero hero) {
        System.out.println("--------------不能跑动---------------");
        try {
            Thread.sleep(2000);//假设眩晕持续2秒
        } catch (InterruptedException e) {}
        hero.setState(Hero.COMMON);
        System.out.println("------眩晕状态结束,变为正常状态------");
    }
}
复制代码

Hero.java

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

    public static final RunState COMMON = new CommonState();//正常状态

    public static final RunState SPEED_UP = new SpeedUpState();//加速状态

    public static final RunState SPEED_DOWN = new SpeedDownState();//减速状态

    public static final RunState SWIM = new SwimState();//眩晕状态

    private RunState state = COMMON;//默认是正常状态

    private Thread runThread;//跑动线程

    //设置状态
    public void setState(RunState state) {
        this.state = state;
    }

    //停止跑动
    public void stopRun() {
        if (isRunning()) {
            runThread.interrupt();
        }
        System.out.println("--------------停止跑动---------------");
    }

    //开始跑动
    public void startRun() {
        if (isRunning()) {
            return;
        }
        final Hero hero = this;
        runThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (!runThread.isInterrupted()) {
                    state.run(hero);
                }
            }
        });
        System.out.println("--------------开始跑动---------------");
        runThread.start();
    }

    private boolean isRunning() {
        return runThread != null && !runThread.isInterrupted();
    }

}
复制代码

测试:

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Hero hero = new Hero();
        hero.startRun();
        hero.setState(Hero.SPEED_UP);
        Thread.sleep(5000);
        hero.setState(Hero.SPEED_DOWN);
        Thread.sleep(5000);
        hero.setState(Hero.SWIM);
        Thread.sleep(5000);
        hero.stopRun();
    }
}
复制代码

结果:

--------------开始跑动--------------- --------------加速跑动--------------- ------加速状态结束,变为正常状态------ --------------减速跑动--------------- ------减速状态结束,变为正常状态------ --------------不能跑动--------------- ------眩晕状态结束,变为正常状态------ --------------停止跑动---------------


总结

状态模式与策略模式区别 状态模式和策略模式的 UML 一样,但是解决的问题和侧重不一样。

  1. 状态模式重点在各状态之间的切换从而做不同的事情,而策略模式更侧重于根据具体情况选择策略,并不涉及切换。
  2. 状态模式不同状态下做的事情不同,而策略模式做的都是同一件事,例如聚合支付平台,有支付宝、微信支付、银联支付,虽然策略不同,但最终做的事情都是支付,也就是说他们之间是可替换的。反观状态模式,各个状态的同一方法做的是不同的事,不能互相替换。
  3. 状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而通过从Context中分离出策略或算法,我们可以重用它们。
  4. 在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。

本文系转载,前往查看

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

本文系转载前往查看

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概述
  • 通用代码
  • 具体实例
  • 总结
相关产品与服务
云支付
云支付(Cloud Pay,CPay)为您提供开放、可靠的聚合收款技术服务和商户管理功能。云支付支持刷卡支付、扫码支付、一码多付多种支付方式。服务商也可使用云支付提供的 SDK 和 HTTPS 接口,将云支付集成进自己的系统中,为商户提供的个性化解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档