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

前言

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

状态模式

概念介绍

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

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

流程结构如下图:

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

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

举例

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

先创建一个休假申请单类

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

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

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

}

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


 * 审批单状态接口
 interface ApplyState {

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

}

待提交状态


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

审核中状态


 * 审核中状态
 class Audit  changeHandle() {
        System.out.println("申请单处于审核中状态,当用户查看申请单详情时跳转到详情页可以看到提交记录。");
    }
}

审核通过状态


 *
 * 审核通过状态
 class Pass  changeHandle() {
        System.out.println("申请单已经审批通过,当前用户可以正常休假了。");
    }
}

审核未通过状态


 * 审核未通过状态
 class NotPass  changeHandle() {
        System.out.println("申请单未通过审核,当前用户不可以休假");
    }
}

测试类

 TestOA {

    static  main(String[] args) {

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

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

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

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

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


    }
}

运行结果:

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

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

结构分析

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

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

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

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

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

总结

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

主要优点

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

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

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

主要缺点

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

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

使用场景

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

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

 

 

 

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

 

这个是我的个人公众号,文章以后也会同步到公众号上去,欢迎关注。

 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,它是针对软件开发中经常遇到的一些设计问题,总结出来的一套通用的解决方案。
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中,使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
迭代器模式提供了一种方法,用于遍历集合对象中的元素,而又不暴露其内部的细节。
外观模式又叫门面模式,它提供了一个统一的(高层)接口,用来访问子系统中的一群接口,使得子系统更容易使用。
单例模式(Singleton Design Pattern)保证一个类只能有一个实例,并提供一个全局访问点。
组合模式可以将对象组合成树形结构来表示“整体-部分”的层次结构,使得客户可以用一致的方式处理个别对象和对象组合。
装饰者模式能够更灵活的,动态的给对象添加其它功能,而不需要修改任何现有的底层代码。
观察者模式(Observer Design Pattern)定义了对象之间的一对多依赖,当对象状态改变的时候,所有依赖者都会自动收到通知。
代理模式为对象提供一个代理,来控制对该对象的访问。代理模式在不改变原始类代码的情况下,通过引入代理类来给原始类附加功能。
工厂模式(Factory Design Pattern)可细分为三种,分别是简单工厂,工厂方法和抽象工厂,它们都是为了更好的创建对象。
状态模式允许对象在内部状态改变时,改变它的行为,对象看起来好像改变了它的类。
命令模式将请求封装为对象,能够支持请求的排队执行、记录日志、撤销等功能。
备忘录模式(Memento Pattern)保存一个对象的某个状态,以便在适当的时候恢复对象。备忘录模式属于行为型模式。 基本介绍 **意图:**在不破坏封装性的前提下,捕获一个对象的内部状态,并在该
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为
享元模式(Flyweight Pattern)(轻量级)(共享元素)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结