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设计模式概述

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

原文地址:https://www.cnblogs.com/jimoer/p/9715937.html

时间: 2024-10-14 07:23:24

Java设计模式学习记录-状态模式的相关文章

Java设计模式学习记录-桥接模式

前言 这次介绍结构型设计模式中的第二种模式,桥接模式. 使用桥接模式的目的就是为了解耦,松散的耦合更利于扩展,但是会增加相应的代码量和设计难度. 桥接模式 桥接模式是为了将抽象化与实现化解耦,让二者可以独立地变化.方便对每一部分的扩展,以及单独的维护.抽象化的一方与实现化的一方之间建立一个桥梁,这样两者的依赖关系就可以通过这个桥梁来建立了. 举例 三个小动物要过河,分别是小猪,小鸡,小马,小猪要去河对面的空地晒太阳,小鸡要去河对面的小树林里找虫子吃,小马要去河对面的草地里吃草.那么它们三个都要经

Java设计模式学习记录-迭代器模式

前言 这次要介绍的是迭代器模式,也是一种行为模式.我现在觉得写博客有点应付了,前阵子一天一篇,感觉这样其实有点没理解透彻就写下来了,而且写完后自己也没有多看几遍,上次在面试的时候被问到java中的I/O的各种实现用到了什么设计模式,我愣是想半天没想出来了,人家还给提示了我也没想出来,最后还是面试官给出的答案,是装饰模式,听到答案后就恍然大悟了,前两天刚看了装饰模式,还写下了I/O操作中的各种类都是用到了装饰模式,后来想想两方面原因造成的当时没回答出来,一是面试时紧张就容易想不起来,二是对设计模式

Java设计模式学习记录-装饰模式

前言 装饰模式也是一种结构型模式,主要是目的是相对于类与类之间的继承关系来说,使用装饰模式可以降低耦合度.JDK中有不少地方都使用到了装饰模式,例如Java的各种I/O流,javax.swing包中一些图形界面构件功能的增强等地方都运用了装饰模式. 装饰模式 定义 装饰模式的定义是:在不改变原类文件以及不使用继承的情况下,动态的扩展一个对象的功能.装饰模式是通过创建一个包装对象来实现的,也就是用装饰来包裹真实的对象. 举例 还是老规矩,举例说明,在给亲朋好友过生日时会买生日蛋糕,然后生日蛋糕又有

设计模式学习之-状态模式

一.状态模式状态模式,当一个对象的内在状态发生改变时允许改变其行为行为,这个对象像是改变了其子类.状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况.把状态的判断逻辑转移到表示不同的状态的一系列类当中,可以把复杂的判断逻辑简化.当然,如果这个状态判断比较简单,那就没有必要用“状态模式”了.这段话有点难以理解,简而言之就是,在一类中根据当前状态去实例化下一状态子类.下面是状态模式结构图. State类,是一个抽象状态类,定义一个接口以封装与Context的特定状态相关的行为.

《Java设计模式》之状态模式

状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式. 状态模式允许一个对象在其内部状态改变的时候改变其行为.这个对象看上去就像是改变了它的类一样. 定义与结构 GOF<设计模式>中给状态模式下的定义为:允许一个对象在其内部状态改变时改变它的行为.这个对象看起来似乎修改了它的类.看起来,状态模式好像是神通广大--居然能够"修改自身的类"! 能够让程序根据不同的外部情况来做出不同的响应,最直接的方法就是在程序中将这

Java设计模式系列之状态模式

状态模式(State)的定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新.允许一个对象在其内部状态改变时改变它的行为.对象看起来似乎修改了它的类 状态模式(State)适用性 1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为. 2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态. 这个状态通常用一个或多个枚举常量表示. 通常,有多个操作包含这一相同的条件结构. State模式将每一个条件分支

Java设计模式学习三-----工厂模式

工厂模式 工厂模式(Factory Pattern)是Java中最常用的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 在工厂模式中,创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象. 工厂模式的思路:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行.使用过程中做好接口选择. 优点:1.一个调用者向创建一个对象,只要知道名称就可以了.2.扩展性高,如果想增加一个产品,只要扩展一个工厂

Java设计模式学习记录-单例模式

前言 已经介绍和学习了两个创建型模式了,今天来学习一下另一个非常常见的创建型模式,单例模式. 单例模式也被称为单件模式(或单体模式),主要作用是控制某个类型的实例数量是一个,而且只有一个. 单例模式 单例模式的实现方式 实现单例模式的方式有很多种,大体上可以划分为如下两种. 外部方式 在使用某些全局对象时,做一些“try-Use”的工作.就是如果要使用的这个全局对象不存在,就自己创建一个,把它放到全局的位置上:如果本来就有,则直接拿来使用. 内部实现方式 类型自己控制正常实例的数量,无论客户程序

Java设计模式学习记录-简单工厂模式、工厂方法模式

前言 之前介绍了设计模式的原则和分类等概述.今天开启设计模式的学习,首先要介绍的就是工厂模式,在介绍工厂模式前会先介绍一下简单工厂模式,这样由浅入深来介绍. 简单工厂模式 做法:创建一个工厂(方法或类)用来制造对象. 当一个人想要用手机的时候,需要自己创建手机然后来使用. 如下: public class IphoneX { public IphoneX(){ System.out.println("##### 制造iphoneX #####"); } } public class I