设计模式内容分享(十八):状态模式

这篇具有很好参考价值的文章主要介绍了设计模式内容分享(十八):状态模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、状态模式是什么

二、状态模式的适用场景

三、状态模式结构

四、状态模式实现方式

五、状态模式的实现

六、状态模式的优缺点

七、状态模式和其他模式的区别

八、总结



设计模式内容分享(十八):状态模式,设计模式 内容分享,设计模式,状态模式

一、状态模式是什么

在软件开发过程中,应用程序中的某些对象会根据不同的情况做出不同的行为,这种对象称为有状态的对象,而把影响对象行为的不同的情况称为状态。当有状态的对象与外部事件产生互动时,其内部状态会发生改变,从而影响其行为。

  • 【定义】

    对有状态的对象,把复杂的判断逻辑提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。属于行为型模式。

    不同的类表示不同情况的状态,以此消除 if-else、switch-case 等冗余语句,代码更有层次性,并且具备良好的扩展性。

  • 【主要作用】

    可以根据对象所依赖状态的改变而改变它的相关行为。

  • 【核心思想】

    程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个状态切换到另一个状态。

设计模式内容分享(十八):状态模式,设计模式 内容分享,设计模式,状态模式

二、状态模式的适用场景

  • 【适用场景】

    • 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。

    • 一个操作中含有很多的多分支结构,并且这些分支取决于对象的状态。

  • 【生活实例】

    • 人的高兴、伤心的不同情绪有不同的行为。

    • 线程有新建、运行、阻塞,等待状态,超时等待状态和死亡 6 种状态。

    • 播放器的暂停、播放。

    • 手机的解锁,锁定状态。

三、状态模式结构

  • 上下文(Context)角色:定义了客户端需要的接口,内部持有一个具体状态对象的引用,并负责具体状态的切换。

  • 抽象状态(State)角色:声明特定于状态方法的接口,用以封装上下文角色中的特定状态所对应的行为,可以有一个或多个行为。

  • 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

    当多个状态有部分相似行为方法时, 可以提供一个封装有部分通用行为的中间抽象类。

  • 客户端(Client)角色:定义上下文角色,执行状态行为。

设计模式内容分享(十八):状态模式,设计模式 内容分享,设计模式,状态模式

四、状态模式实现方式

  • 确定上下文类,定义状态转变的方法,并定义对抽象状态的引用。

  • 定义抽象状态角色,声明状态变化之后的行为方法。

  • 为每个实际状态创建一个继承于状态接口的类。在每个具体状态类中实现该状态对应的。

    当多个状态有部分相似行为方法时, 可以提供一个封装有部分通用行为的中间抽象类。

    • 将通用成员变量或方法设为公有。

    • 抽取的上下文行为更改为上下文中的公有方法, 然后在状态类中调用。

  • 定义上下文角色,初始化状态,行为执行。

五、状态模式的实现

【案例】:线程的状态切换。

设计模式内容分享(十八):状态模式,设计模式 内容分享,设计模式,状态模式

【案例说明】:在我们日常开发工作中,线程是经常会是用的一种技术手段,线程有新建、运行、阻塞,等待状态,超时等待状态和死亡 6 种状态,在不同的状态下有不同的行为。在此案例中:

  1. 上下文(Context)角色持有一个线程的当前状态,并为其初始化状态,提供转换到其他状态的方法。

  2. 抽象状态(State)角色只作为一个基类,指定状态名字,具体实现由具体的状态类实现。

  3. 具体状态(Concrete State)角色实现每个状态的具体行为

设计模式内容分享(十八):状态模式,设计模式 内容分享,设计模式,状态模式

  • 上下文(Context)角色

    import lombok.Data;
    
    /**
     * 上下文(Context)角色  提供转换到其他状态的方法
     * @author Edwin
     * @date 2021/11/21 15:55  
     */
    @Data
    publicclass Context {
    
        /**
         * 持有一个线程的当前状态
         * @author Edwin
         * @date 2021/11/21 17:08
         */
        private TheadState state;
    
        /**
         * 初始化线程的当前状态
         * @author Edwin
         * @date 2021/11/21 17:09
         */
        Context() {
            state = new TheadNew();
        }
    
    
        /**
         * 开启一个新的线程
         * @author Edwin
         * @date 2021/11/21 17:11
         */
        public void start() {
            ((TheadNew) state).start(this);
        }
    
    
        /**
         *  阻塞状态线程恢复到运行状态
         * @author Edwin
         * @date 2021/11/21 17:03
         */
        public void resume() {
            ((TheadBlocked) state).resume(this);
        }
    
    
        /**
         * 阻塞当前线程
         * @author Edwin
         * @date 2021/11/21 16:57
         */
        public void sync() {
            ((TheadRunnable) state).sync(this);
        }
    
        /**
         * 当前线程进入等待状态
         * @author Edwin
         * @date 2021/11/21 17:00
         */
        public void await() {
            ((TheadRunnable) state).wait(this);
        }
    
        /**
         * 当前线程进入超时等待状态状态
         * @author Edwin
         * @date 2021/11/21 17:00
         */
        public void sleep() {
            ((TheadRunnable) state).sleep(this);
        }
    
        /**
         * 停止线程
         * @author Edwin
         * @date 2021/11/21 16:54
         */
        public void stop() {
            ((TheadRunnable) state).stop(this);
        }
    
    
        /**
         * 线程在睡眠指定时间后自动唤醒恢复到运行状态
         * @author Edwin
         * @date 2021/11/21 17:00
         * @return null
         */
        public void wake() {
            ((TheadTimedwaiting) state).wake(this);
        }
    
    
        /**
         * 线程恢复到运行状态
         * @author Edwin
         * @date 2021/11/21 17:00
         */
        public void notice() {
            ((TheadWaiting) state).notify(this);
        }
    
    }
    
    
  • 抽象状态(State)角色

    /**
     * 抽象状态(State)角色:线程状态
     * @author Edwin
     * @date 2021/11/21 15:56
     */
    publicabstractclass ThreadState {
    
        /**
         *  线程的当前状态名字,没有什么具体实际意义
         * @author Edwin
         * @date 2021/11/21 16:02
         */
        public String threadName;
    }
    
    • 线程状态枚举

      Java中Thread类中State枚举类定义与说明

      publicenum State {
          /**
           *  新建状态
           */
          NEW,
          /**
           * 运行状态
           * java线程中将操作系统中的就绪状态(ready)和运行中状态(running)统一归类为可运行状态(RUNNABLE)。
           */
          RUNNABLE,
          /**
           * 阻塞状态
           */
          BLOCKED,
          /**
           * 等待状态
           * 进入该状态的线程需要等待其它线程进行一些特殊操作,如notify、notifyAll、unpark
           *
           * 触发条件:调用下列任何一个方法
           * Object#wait()
           * join()
           * LockSupport#park()
           */
          WAITING,
          /**
           * 超时等待状态
           * 该状态与WAITING不同之处是在指定时间后可以自动唤醒到就绪状态;
           *
           * 触发条件:调用下列任何一个方法
           * sleep Thread.sleep
           * Object#wait(long)
           * join(long)
           * LockSupport#parkNanos
           * LockSupport#parkUntil
           */
          TIMED_WAITING,
          /**
           * 终止状态
           */
          TERMINATED;
      }
      
  • 具体状态(Concrete State)角色

    /**
     * 具体状态(Concrete State)角色 : 新建状态
     * @author Edwin
     * @date 2021/11/21 16:04
     */
    publicclass ThreadNew extends ThreadState {
    
    
        /**
         *  初始化新建状态
         * @author Edwin
         * @date 2021/11/21 16:05
         */
        public ThreadNew() {
            threadName = Thread.State.NEW.name();
            System.out.println("当前线程处于:新建状态.");
        }
    
        /**
         * 调用线程的start方法 开启一个新的线程
         * @author Edwin
         * @date 2021/11/21 16:44
         */
        public void start(Context context) {
            System.out.print("调用start()方法,获取CPU的执行时间-->");
            if (Thread.State.NEW.name().equals(threadName)) {
                context.setState(new ThreadRunnable());
            } else {
                System.out.println("当前线程不是新建状态,不能调用start()方法.");
            }
        }
    }
    
    /**
     * 具体状态(Concrete State)角色 : 运行状态
     * @author Edwin
     * @date 2021/11/21 16:04
     */
    publicclass ThreadRunnable extends ThreadState {
    
        /**
         *  运行状态
         * @author Edwin
         * @date 2021/11/21 16:05
         */
        public ThreadRunnable() {
            threadName = Thread.State.RUNNABLE.name();
            System.out.println("当前线程处于:运行状态.");
        }
    
        /**
         * 模拟 synchronized 进入阻塞状态
         * @author Edwin
         * @date 2021/11/21 16:57
         */
        public void sync(Context context) {
            if (ThreadStateEnum.RUNNABLE.name().equals(threadName)) {
                System.out.print("调用sync()方法,线程进入阻塞状态-->");
                context.setState(new ThreadBlocked());
            } else {
                System.out.println("当前线程不是运行状态,不能调用sync()方法.");
            }
        }
    
        /**
         * 模拟当前线程对象调用wait()方法。进入等待状态
         * @author Edwin
         * @date 2021/11/21 17:00
         */
        public void wait(Context context) {
            if (Thread.State.RUNNABLE.name().equals(threadName)) {
                System.out.print("调用wait()方法,线程进入等待状态-->");
                context.setState(new ThreadWaiting());
            } else {
                System.out.println("当前线程不是运行状态,不能调用wait()方法.");
            }
        }
    
        /**
         * 模拟当前线程对象调用Thread.sleep(long)方法。进入超时等待状态状态
         * @author Edwin
         * @date 2021/11/21 17:00
         */
        public void sleep(Context context) {
            System.out.print("调用sleep()方法,线程进入超时等待状态-->");
            if (Thread.State.RUNNABLE.name().equals(threadName)) {
                context.setState(new ThreadTimedwaiting());
            } else {
                System.out.println("当前线程不是运行状态,不能调用sleep()方法.");
            }
        }
    
        /**
         * 调用stop() 停止线程
         * @author Edwin
         * @date 2021/11/21 16:54
         */
        public void stop(Context context) {
            if (Thread.State.RUNNABLE.name().equals(threadName)) {
                System.out.print("调用stop()方法,停止当前线程-->");
                context.setState(new ThreadTerminated());
            } else {
                System.out.println("当前线程不是运行状态,不能调用stop()方法.");
            }
        }
    }
    
    /**
     * 具体状态(Concrete State)角色 : 阻塞状态
     * @author Edwin
     * @date 2021/11/21 16:04
     */
    publicclass ThreadBlocked extends ThreadState {
    
        /**
         *  阻塞状态
         * @author Edwin
         * @date 2021/11/21 16:05
         * @return null
         */
        public ThreadBlocked() {
            threadName = Thread.State.BLOCKED.name();
            System.out.println("当前线程处于:阻塞状态.");
        }
    
        /**
         *  阻塞状态线程取得锁  恢复到运行状态
         * @author Edwin
         * @date 2021/11/21 17:03
         */
        public void resume(Context context) {
            if (Thread.State.BLOCKED.name().equals(threadName)) {
                System.out.print("调用resume()方法,线程恢复到运行状态-->");
                context.setState(new ThreadRunnable());
            } else {
                System.out.println("当前线程不是阻塞状态,不能调用resume()方法.");
            }
        }
    
    }
    
    /**
     * 具体状态(Concrete State)角色 : 等待状态
     * @author Edwin
     * @date 2021/11/21 16:04
     */
    publicclass ThreadWaiting extends ThreadState {
        /**
         *  等待状态
         * @author Edwin
         * @date 2021/11/21 16:05
         */
        public ThreadWaiting() {
            threadName = Thread.State.WAITING.name();
            System.out.println("当前线程处于:等待状态.");
        }
        /**
         * 模拟其它线程调用notify、notifyAll、unpark  线程恢复到运行状态
         * @author Edwin
         * @date 2021/11/21 17:00
         */
        public void notify(Context context) {
            if (Thread.State.WAITING.name().equals(threadName)) {
                System.out.print("调用notify()方法,线程恢复到运行状态-->");
                context.setState(new ThreadRunnable());
            } else {
                System.out.println("当前线程不是运行状态,不能调用notify()方法.");
            }
        }
    }
    
    /**
     * 具体状态(Concrete State)角色 : 超时等待状态
     * @author Edwin
     * @date 2021/11/21 16:04
     */
    publicclass ThreadTimedwaiting extends ThreadState {
    
        /**
         *  超时等待状态
         * @author Edwin
         * @date 2021/11/21 16:05
         * @return null
         */
        public ThreadTimedwaiting() {
            threadName = Thread.State.TIMED_WAITING.name();
            System.out.println("当前线程处于:超时等待状态.");
        }
    
        /**
         * 模拟线程在睡眠指定时间后自动唤醒恢复到运行状态
         * @author Edwin
         * @date 2021/11/21 17:00
         */
        public void wake(Context context) {
            if (ThreadStateEnum.TIMED_WAITING.name().equals(threadName)) {
                System.out.print("调用wake()方法,线程自动唤醒恢复到运行状态-->");
                context.setState(new ThreadRunnable());
            } else {
                System.out.println("当前线程不是运行状态,不能调用wake()方法.");
            }
        }
    
    }
    
    /**
     * 具体状态(Concrete State)角色 : 终止状态
     * @author Edwin
     * @date 2021/11/21 16:04
     */
    publicclass ThreadTerminated extends ThreadState {
        /**
         *  终止状态
         * @author Edwin
         * @date 2021/11/21 16:05
         */
        public ThreadTerminated() {
            threadName = Thread.State.TERMINATED.name();
            System.out.println("当前线程处于:终止状态.");
        }
    }
    
    • 运行状态

    • 终止状态

    • 超时等待状态

    • 等待状态

    • 阻塞状态

    • 运行状态

    • 新建状态

  • 客户端代码实现

    public static void main(String[] args) {
        // 定义上下文角色
        System.out.print("定义上下文角色=========>>>>>>>>>");
        Context context = new Context();
        System.out.print("执行当前线程===========>>>>>>>>>");
        context.start();
        System.out.print("当前线程进入等待状态=======>>>>>>");
        context.await();
        System.out.print("唤醒当前线程进入运行状态====>>>>>>");
        context.notice();
        System.out.print("当前线程进入阻塞状态======>>>>>>>");
        context.sync();
        System.out.print("阻塞线程获得锁进入运行状态====>>>>");
        context.resume();
        System.out.print("当前线程进入等待状态状态=====>>>>>");
        context.sleep();
        System.out.print("当前睡眠线程进入运行状态=========>>>>>>>>>");
        context.wake();
        System.out.print("停止线程当前线程=========>>>>>>>>>");
        context.stop();
    }
    
  • 案例输出结果

设计模式内容分享(十八):状态模式,设计模式 内容分享,设计模式,状态模式

六、状态模式的优缺点

  • 优点

  • 满足单一职责原则,特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,结构清晰。

    • 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。

    • 状态转换显示化,减少对象间的相互依赖。通过消除臃肿的状态机条件语句简化上下文代码。

  • 缺点

    • 状态模式的使用必然会增加系统的类与对象的个数。

    • 状态模式的结构与实现都较为复杂,增加系统的复杂度。

    • 状态模式对开闭原则的支持并不太好,增加新的状态类和行为都需要修改源码。

七、状态模式和其他模式的区别

  • 【状态模式】和【责任链模式】都能消除 if-else 分支过多的问题。但在某些情况下,状态模式中的状态可以理解为责任,那么在这种情况下,两种模式都可以使用。

    • 【状态模式】强调的是一个对象内在状态的改变,各个状态对象知道自己要进入的下一个状态对象。

    • 【责任链模式】强调的是外部节点对象间的改变,并不清楚其下一个节点处理对象,链式组装由客户端负责。

  • 【状态模式】和【策略模式】的 UML 类图架构几乎一样,但应用场景不一样

    • 【策略模式】多种算法行为是独立的,任何一种都能满足业务,客户端可自行更换策略算法。

    • 【状态模式】各个状态在一定条件下可以自动切换到其他状态,客户端只能设置初始状态,无法指定状态。

八、总结

状态模式的使用免去了过多的if–else判断,但是会造成更多的接口和类,所以对于非常简单的状态判断,不建议使用。当状态的个数有限并且相互独立的时候可以考虑使用状态模式。

 文章来源地址https://www.toymoban.com/news/detail-798163.html

到了这里,关于设计模式内容分享(十八):状态模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 软件工程(十八) 行为型设计模式(四)

    简要说明 允许一个对象在其内部改变时改变它的行为 速记 状态变成类 类图如下 状态模式主要用来解决对象在多种状态转换时,需要对外输出不同的行为的问题。比如订单从待付款到待收货的咋黄台发生变化,执行的逻辑是不一样的。 所以我们将状态抽象为一个接口

    2024年02月11日
    浏览(56)
  • 设计模式:状态模式示例

    状态模式可以应用于多种场景,下面是一些示例及其代码实现: 1. 交通信号灯 交通信号灯(红灯、绿灯、黄灯)根据当前状态切换到下一个状态。 2. 游戏角色等级系统 游戏中的角色根据经验值提升等级,不同等级有不同的行为。 这两个示例展示了状态模式在不同场景下的

    2024年04月23日
    浏览(28)
  • 设计模式-状态模式

    一个对象有状态变化 每次状态变化都会触发一个逻辑 不能总是用 if else 来控制 交通信号灯不同颜色的变化 传统UML类图 简化后的UML类图 有限个状态、以及在这些状态之间的变化 如交通信号灯 使用开源lib:javascript-state-machine github.com/jakesgordon/javascript-state-machine 有限状态机

    2024年02月07日
    浏览(42)
  • 设计模式_状态模式

    介绍 设计模式 定义 案例 问题堆积在哪里 解决办法 状态模式 一个对象 状态可以发生改变 不同的状态又有不同的行为逻辑 游戏角色 加载不同的技能 每个技能有不同的:攻击逻辑 攻击范围 动作等等 1 状态很多 2 每个状态有自己的属性和逻辑 每种状态单独写一个类 角色需要

    2024年02月06日
    浏览(36)
  • 设计模式(18):状态模式

    用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题 环境类(Context): 环境类中维护一个State对象,它定义了当前的状态,并委托当前状态处理一些请求; 抽象状态类(State): 用于封装对象的一个特定状态所对应的行为; 具体状态类(ConcreteState): 实现了抽象状态类

    2024年04月09日
    浏览(39)
  • 《设计模式》状态模式

    定义 : 状态模式也称为状态机模式, 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。 属于 行为型 模式。 状态模式的角色组成 : State(抽象状态类) :定义一个接口用来封装与环境类的一个特定状态相关的行为,可以有一个或多个行为。 Con

    2024年02月05日
    浏览(34)
  • 【设计模式】订单状态流传中的状态机与状态模式

    状态模式一般是用在对象内部的 状态流转 场景中,用来实现 状态机 。 什么是状态机呢? 状态机是对状态转移的抽象,由 事件 、 状态 、 动作 组成,事件有时候也被称为 转移事件 或者 转移 ,当事件触发时,可以将状态由一个状态变更为另一个状态,并执行动作。其中,

    2024年02月12日
    浏览(41)
  • 设计模式之状态模式(下)

    3)共享状态 1.概述 在某些情况下,多个环境对象可能需要共享同一个状态,如果希望在系统中实现多个环境对象共享一个或多个状态对象,那么需要将这些状态对象定义为环境类的静态成员对象。 2.案例 背景 :要求两个开关对象要么都处于开的状态,要么都处于关的状态,

    2024年04月25日
    浏览(30)
  • 设计模式浅析(十一) ·状态模式

    日常叨逼叨 java设计模式浅析,如果觉得对你有帮助,记得一键三连,谢谢各位观众老爷😁😁 状态模式 概念 状态模式 Java中的状态模式(State Pattern)是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为,看起来就像修改了它的类一样。状态模式的核心

    2024年04月12日
    浏览(33)
  • 【前端设计模式】之状态模式

    在前端开发中,我们经常需要处理复杂的应用状态。这时候,状态模式就能派上用场了。状态模式允许我们根据不同的状态来改变对象的行为,从而实现优雅地管理应用状态。 状态模式具有以下特性: 状态(State):定义了对象在特定条件下所处的行为和属性。 上下文(C

    2024年01月20日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包