专栏首页JimoerJava设计模式学习记录-状态模式

Java设计模式学习记录-状态模式

前言

状态模式是一种行为模式,用于解决系统中复杂的对象状态转换以及各个状态下的封装等问题。状态模式是将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象的状态可以灵活多变。这样在客户端使用时无需关心对象的状态,可以实现自身的一致性处理。最近工作有些忙,更新博客慢了。还是要严格要求自己的,抽时间也要坚持学习。 

状态模式

概念介绍

状态模式允许一个对象在其状态改变时,改变它的行为,对象看起来似乎修改了它的类。

想要在改变自身状态时改变对象行为,最直接的方法就是在代码中将所有可能发生的情况都考虑到了,然后使用if-else语句来进行相应的选择。但是这种方法对于复杂的状态判断会显得杂乱无章,容易产生错误;而且增加一个新的状态将会带来大量的修改。

流程结构如下图:

此时“能够修改自身”的状态模式的引入也许是个不错的主意,将不同条件下的行为封装在一个类里,再给这些类一个统一的父类来约束它们。

就会变成如下图流程结构:

举例

还是来举个具体的实例来说明一下吧。同事小王要请假,根据公司规定,请假要先在OA上提请假申请单,然后审批通过后就可以正常休假了。这个请假申请单大致经历这么几个状态,未审核(待提交)、审核中、审核通过、审核未通过,这里只是粗略的分为这几个状态。下面我们使用状态模式来模拟实现一下这个请假申请单的状态流转过程。

先创建一个休假申请单类

/**
 * 休假申请
 */
public class LeaveApply {
    /**
     * 休假申请单初始状态是待提交状态
     */
    private ApplyState applyState = new UnAudited();

    /**
     * 设置状态
     * @param state
     */
    public void setState(ApplyState state){
        applyState = state;
    }

    /**
     * 状态变化后,更新对象自身的行为
     */
    public void update(){
        applyState.changeHandle();
    }

}

审批单状态接口,声明统一处理的方法。

/**
 * 审批单状态接口
 */
public interface ApplyState {

    /**
     * 状态变化处理操作
     */
    void changeHandle();

}

待提交状态

/**
 * 未审核状态(待提交审核)
 */
public class UnAudited implements ApplyState {
    /**
     * 状态变化处理操作
     */
    @Override
    public void changeHandle() {
        System.out.println("申请单处于未审核状态,当用户查看申请单详情时直接跳转到编辑页。");
    }
}

审核中状态

/**
 * 审核中状态
 */
public class Audit implements ApplyState {
    /**
     * 状态变化处理操作
     */
    @Override
    public void changeHandle() {
        System.out.println("申请单处于审核中状态,当用户查看申请单详情时跳转到详情页可以看到提交记录。");
    }
}

审核通过状态

/**
 *
 * 审核通过状态
 */
public class Pass implements ApplyState {
    /**
     * 状态变化处理操作
     */
    @Override
    public void changeHandle() {
        System.out.println("申请单已经审批通过,当前用户可以正常休假了。");
    }
}

审核未通过状态

/**
 * 审核未通过状态
 */
public class NotPass implements ApplyState {
    /**
     * 状态变化处理操作
     */
    @Override
    public void changeHandle() {
        System.out.println("申请单未通过审核,当前用户不可以休假");
    }
}

测试类

public class TestOA {

    public static void main(String[] args) {

        //创建一个请假申请单
        LeaveApply leaveApply = new LeaveApply();

        leaveApply.setState(new UnAudited());
        leaveApply.update();

        leaveApply.setState(new Audit());
        leaveApply.update();

        leaveApply.setState(new Pass());
        leaveApply.update();

        leaveApply.setState(new NotPass());
        leaveApply.update();


    }
}

运行结果:

申请单处于未审核状态,当用户查看申请单详情时直接跳转到编辑页。
申请单处于审核中状态,当用户查看申请单详情时跳转到详情页可以看到提交记录。
申请单已经审批通过,当前用户可以正常休假了。
申请单未通过审核,当前用户不可以休假

这个例子如果是不使用状态模式的思想,而是使用条件语句来实现就会出现很多的if-else来进行判断什么状态,应该执行什么样的方法。现在把各个状态的处理逻辑分离,结构清晰了并且耦合也不那么紧密了。

结构分析

在状态模式中引入了抽象状态类和具体状态类,它们是状态模式的核心。状态模式的结构组成如下图:

在状态模式中,主要涉及了如下几个角色。

环境角色(Context):定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。

抽象状态角色(State):定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。

具体状态角色(Contract):每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

总结

状态模式在功能上和策略模式很类似,但是在实现思想上状态模式是将各个状态分离解耦的,并且可以将对象的具体行为委托给当前的状态对象,而策略模式中,策略的选择是根据Context类中的行为来确定的,也不存在各个状态的切换。在实际开发中,状态模式具有较高的使用频率,在工作流和游戏开发中状态模式都得到了广泛的应用,例如公文状态的转换、游戏中角色的升级等。

主要优点

1、封装了状态的转换规则,在状态模式中可以将状态转换的工作封装在环境类或具体的状态类中,可以对状态转换码进行集中管理,而不是分散在一个个的业务中。

2、将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。

3、允许状态转换逻辑与状态对象合为一体,而不是提供一个巨大的条件语句块,状态模式可以让我们避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。

主要缺点

1、状态模式的使用必然会增加系统中类和对象的个数,导致系统运行开销增大。

2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,增加系统设计的难度。

使用场景

1、对象的行为依赖于它的状态(如某些属性值),状态的改变将导致行为的变化。

2、在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强。

想了解更多的设计模式请查看Java设计模式学习记录-GoF设计模式概述

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java设计模式学习记录-备忘录模式

    这次要介绍的是备忘录模式,也是行为模式的一种 。现在人们的智能手机上都会有备忘录这样一个功能,大家也都会用,就是为了记住某件事情,防止以后自己忘记了。那么备忘录...

    Jimoer
  • Java设计模式学习记录-模板方法模式

    模板方法模式,定义一个操作中算法的骨架,而将一些步骤延迟到子类中。使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。

    Jimoer
  • JVM学习记录-垃圾回收算法

    Jimoer
  • 23种设计模式之状态模式

    通俗的说, 就是一个事物有不同的状态,在不同状态下执行各个方法时有不同的表现, 将每个状态都封装成一个类, 然后通过上下文对象统一管理

    烟草的香味
  • 设计模式(十五)状态模式

    前言 建议在阅读本文前先阅读设计模式(十一)策略模式这篇文章,虽说状态模式和策略模式的结构几乎是相同的,但是它们所解决的问题是不同的,读完这两篇文章你就会有了答...

    用户1269200
  • UML学习-状态图

    1.状态图概述 状态图(Statechart Diagram)主要用于描述一个对象在其生存期间的动态行为,表现为一个对象所经历的状态序列,引起状态转移的事件(E...

    水击三千
  • 【DeepMind 公开课-深度强化学习教程笔记04】不基于模型的预测

    点击上方“专知”关注获取更多AI知识! 【导读】Google DeepMind在Nature上发表最新论文,介绍了迄今最强最新的版本AlphaGo Zero,不...

    WZEARW
  • Flink HDFS Sink 如何保证 exactly-once 语义

    本文将从源码层面来分析在Flink中是如何保证sink数据到HDFS的exactly-once语义的。

    zhisheng
  • 图论与渡河问题

    大家好,我是南海一号。今天给大家讲一个关于图论的非常有趣的问题。这个问题大家想必都知道,但是它和图论有什么关系呢?就让我给大家讲一下。

    艾木樨
  • 有状态和无状态对象

    这个概念在多线程中一直被提及,实际上很简单。 1.有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线...

    潇洒

扫码关注云+社区

领取腾讯云代金券