【软考】设计模式之状态模式

目录

        • 1. 说明
        • 2. 应用场景
        • 3. 结构图
        • 4. 构成
        • 5. 优缺点
          • 5.1 优点
          • 5.2 缺点
        • 6. java示例
          • 6.1 非状态模式
            • 6.1.1 问题分析
            • 6.1.2 接口类
            • 6.1.2 实现类
            • 6.1.3 客户端
            • 6.1.4 结果截图
          • 6.2 状态模式
            • 6.2.1 抽象状态类
            • 6.2.2 状态类
            • 6.2.3 上下文类
            • 6.2.4 上下文类

1. 说明
  • 1.允许一个对象在其内部状态改变时改变它的行为。
  • 2.对象看起来似乎修改了它的类。
  • 3.对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
2. 应用场景
  • 1.一个对象的行为决定于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  • 2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得开发者可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象独立变化。
3. 结构图

在这里插入图片描述

4. 构成
  • 1.环境角色:Context(上下文)定义客户端感兴趣的接口;维护一个ConcreteState子类的实例,这个实例定义当前状态
  • 2.抽象状态角色:State(状态)定义一个接口以封装与Context的一个特定状态相关的行为
  • 3.具体状态角色:ConcreteState(具体状态子类)每个子类实现与Context的一个状态相关的行为
5. 优缺点
5.1 优点
  • 1.将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
  • 2.允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5.2 缺点
  • 1.状态模式的使用必然会增加系统类和对象的个数。
  • 2.状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
  • 3.状态模式对"开闭原则"的支持并不太好。
6. java示例
6.1 非状态模式
6.1.1 问题分析
  • 1.使用了大量的switch case这样的判断(if else也是一样),使程序的可阅读性变差
  • 2.扩展性差,如果新加了一种状态,则需要修改判断逻辑
6.1.2 接口类
package com.learning.state.before;

/**
 * 电梯接口
 */
public interface ILift {
    //定义四个电梯状态的常量

    /**
     * 打开状态
     */
    int OPENING_STATE = 1;
    /**
     * 关闭状态
     */
    int CLOSING_STATE = 2;
    /**
     * 运行状态
     */
    int RUNNING_STATE = 3;
    /**
     * 停止状态
     */
    int STOPPING_STATE = 4;

    //设置电梯状态的功能
    void setState(int state);

    //电梯操作功能
    void open();

    //电梯关闭功能
    void close();

    //电梯运行功能
    void run();

    //电梯停止功能
    void stop();
}

6.1.2 实现类
package com.learning.state.before;

/**
 * @Description 电梯类
 **/
public class Lift implements ILift{
    //当前电梯状态
    private int state;

    @Override
    public void setState(int state) {
        this.state = state;
    }

    @Override
    public void open() {
        switch(state){
            //如果当前电梯状态是开启状态
            case OPENING_STATE:
                //什么都不做
                break;
            //如果当前电梯状态是关闭状态,打开电梯
            case CLOSING_STATE:
                System.out.println("电梯打开了");
                // 设置当前电梯状态为开启状态
                setState(OPENING_STATE);
                break;
            //如果当前电梯状态是运行状态
            case RUNNING_STATE:
                //什么都不做
                break;
            //如果当前电梯状态是开启状态,打开电梯
            case STOPPING_STATE:
                System.out.println("电梯打开了");
                setState(OPENING_STATE);
                break;

        }
    }

    @Override
    public void close() {
        switch(this.state) {
            case OPENING_STATE:
                //只有开门状态可以关闭电梯门
                System.out.println("电梯关门了");
                //关门之后电梯就是关闭状态了
                this.setState(CLOSING_STATE);
                break;
            case CLOSING_STATE:
                //已经是关门状态,不能关门
                //什么都不做
                break;
            case RUNNING_STATE:
                //运行时电梯门是关着的,不能关门
                //什么都不做
                break;
            case STOPPING_STATE:
                //停止时电梯也是关着的,不能关门
                //什么都不做
                break;
        }
    }

    @Override
    public void run() {
        switch(this.state) {
            case OPENING_STATE:
                //电梯不能开着门运行
                break;
            case CLOSING_STATE:
                //门关了,可以运行了
                System.out.println("电梯运行了");
                //设置为运行状态
                this.setState(RUNNING_STATE);
                break;
            case RUNNING_STATE:
                //已经是运行状态了
                break;
            case STOPPING_STATE:
                System.out.println("电梯运行了");
                //设置为运行状态
                this.setState(RUNNING_STATE);
                break;
        }
    }

    @Override
    public void stop() {
        switch(this.state) {
            case OPENING_STATE:
                // 开门的电梯已经是是停止的了(正常情况下)
                break;
            case CLOSING_STATE:
                // 关门时才可以停止
                System.out.println("电梯停止了");
                this.setState(STOPPING_STATE);
                break;
            case RUNNING_STATE:
                // 运行时当然可以停止了
                System.out.println("电梯停止了");
                this.setState(STOPPING_STATE);
                break;
            case STOPPING_STATE:
                break;
        }
    }
}

6.1.3 客户端
package com.learning.state.before;

/**
 * 客户端
 */
public class Client {
    public static void main(String[] args) {
        // 创建电梯对象
        Lift lift = new Lift();
        // 设置当前电梯的状态
        lift.setState(ILift.OPENING_STATE);

        // 打开
        lift.open();

        lift.close();
        lift.run();
        lift.stop();
    }
}
6.1.4 结果截图

在这里插入图片描述

6.2 状态模式
6.2.1 抽象状态类
package com.learning.state.after;

/**
 * 抽象状态类
 */
public abstract class LiftState {

    // 声明环境角色类变量
    protected Context context;

    public void setContext(Context context){
        this.context = context;
    }

    // 电梯开启操作
    public abstract void open();

    // 电梯关闭操作
    public abstract void close();

    // 电梯运行操作
    public abstract void run();

    // 电梯停止操作
    public abstract void stop();
}

6.2.2 状态类
  • 1.开启状态类
package com.learning.state.after;

/**
 * 开启状态类
 */
public class OpeningState extends LiftState {
    // 当前状态要执行的方法
    @Override
    public void open() {
        System.out.println("电梯开启");
    }

    @Override
    public void close() {
        // 修改状态
        super.context.setLiftState(Context.CLOSING_STATE);
        // 调用当前状态中的context中的close方法
        super.context.close();
    }

    @Override
    public void run() {
        // 什么都不做
    }

    @Override
    public void stop() {
        // 什么都不做
    }
}
  • 2.运行状态类
package com.learning.state.after;

/**
* 运行状态类
*/
public class RunningState extends LiftState {

   /**
    * 运行的时候是不能开电梯门
     */
   @Override
   public void open() {
       // 什么都不做
   }

   /**
    * 运行状态的电梯,门不需要再关
     */
   @Override
   public void close() {
       // 什么都不做
   }

   /**
    * 运行状态下要实现的方法
    */
   @Override
   public void run() {
       System.out.println("电梯正在运行");
   }

   /**
    * 运行状态可以停止
    */
   @Override
   public void stop() {
       super.context.setLiftState(Context.STOPPING_STATE);
       super.context.stop();
   }
}

  • 3.停止状态类
package com.learning.state.after;

/**
 * 停止状态类
 */
public class StoppingState extends LiftState {

    /**
     * 停止状态可以开门
     */
    @Override
    public void open() {
        // 状态修改
        super.context.setLiftState(Context.OPENING_STATE);
        // 动作委托为CloseState来执行,也就是委托给ClosingState子类执行这个动作
        super.context.getLiftState().open();
    }

    /**
     * 可以关门,这个动作不归我执行
     */
    @Override
    public void close() {
        // 状态修改
        super.context.setLiftState(Context.CLOSING_STATE);
        // 动作委托为CloseState来执行,也就是委托给ClosingState子类执行这个动作
        super.context.getLiftState().close();
    }

    /**
     * 停止后,可以再跑起来
     */
    @Override
    public void run() {
        // 状态修改
        super.context.setLiftState(Context.RUNNING_STATE);
        // 动作委托为CloseState来执行,也就是委托给ClosingState子类执行这个动作
        super.context.getLiftState().run();
    }

    /**
     * 停止方法执行
     */
    @Override
    public void stop() {
        System.out.println("电梯停止了");
    }
}

  • 4.关闭状态类
package com.learning.state.after;

/**
 * 关闭状态类
 */
public class ClosingState extends LiftState {

    /**
     * 电梯关闭状态可以再打开
     */
    @Override
    public void open() {
        super.context.setLiftState(Context.OPENING_STATE);
        super.context.open();
    }

    /**
     * 电梯关闭状态实现的动作
     */
    @Override
    public void close() {
        System.out.println("电梯门关闭");
    }

    /**
     * 电梯关门之后启动
     */
    @Override
    public void run() {
        super.context.setLiftState(Context.RUNNING_STATE);
        super.context.run();
    }

    /**
     * 电梯门关着,但没按楼层
     */
    @Override
    public void stop() {
        super.context.setLiftState(Context.STOPPING_STATE);
        super.context.stop();
    }
}
6.2.3 上下文类
package com.learning.state.after;

public class Context {

    // 定义对应状态对象的常量
    public final static OpeningState OPENING_STATE = new OpeningState();

    public final static ClosingState CLOSING_STATE = new ClosingState();

    public final static RunningState RUNNING_STATE = new RunningState();

    public final static StoppingState STOPPING_STATE = new StoppingState();

    // 定义一个当前电梯状态变量
    private LiftState liftState;

    public LiftState getLiftState(){
        return liftState;
    }

    public void setLiftState(LiftState liftState){
        this.liftState = liftState;
        // 设置当前状态对象中的Context对象
        this.liftState.setContext(this);
    }

    public void open(){
        this.liftState.open();
    }

    public void close(){
        this.liftState.close();
    }

    public void run(){
        this.liftState.run();
    }

    public void stop(){
        this.liftState.stop();
    }

}

6.2.4 上下文类
package com.learning.state.after;

/**
 * 客户端类
 */
public class Client {
    public static void main(String[] args) {
        // 创建环境角色对象
        Context context = new Context();
        // 设置当前电梯状态
        context.setLiftState(Context.CLOSING_STATE);

        context.open();
        context.close();
        context.run();
        context.stop();

    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/491077.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

算法之美:二叉树演进之AVL平衡二叉树底层原理

在之前的文章中,我们初步了解了二叉查找树(又称二叉排序树),这使我们意识到使用特定策略的查询可以显著提高查找效率。本文将进一步探讨二叉树的演进。由于树相关算法较多且相对复杂,因为我后续将拆解讲述,…

SUSE 15 SP5 一键安装 Oracle 19C(19.22)单机版

前言 Oracle 一键安装脚本,演示 SUSE 15 SP5 一键安装 Oracle 19C(19.22)单机版过程(全程无需人工干预):(脚本包括 ORALCE PSU/OJVM 等补丁自动安装) ⭐️ 脚本下载地址&#xff1…

集成ES分组查询统计求平均值

前言 之前其实写过ES查询数据,进行分组聚合统计: 复杂聚合分组统计实现 一、目标场景 机房机柜的物联网设备上传环境数据,会存储到ES存到ES的温湿度数据需要查询,进行分组后,再聚合统计求平均值 二、使用步骤 1.引入…

【Linux系统】进程概念创建进程进程标示符

什么是进程? 操作系统中, 进程可以同时存在非常多的。根据我们之前谈的操作系统具有“管理”的特性, 那么就有,既然要管理,就要 --- 先描述,在组织!!! 由冯诺依曼体系结…

AIGC,ChatGPT,Prompt 万能提示词

AIGC ChatGPT 职场案例 AI 绘画 与 短视频制作 PowerBI 商业智能 68集 Mysql 8.0 54集 Oracle 21C 142集 Office 2021实战应用 Python 数据分析实战, ETL Informatica 数据仓库案例实战 51集 Excel 2021实操 100集, Excel 2021函数大全 80集 Excel 2021…

进入消息传递的魔法之门:ActiveMQ原理与使用详解

嗨,亲爱的童鞋们!欢迎来到这个充满魔法的世界,今天我们将一同揭开消息中间件ActiveMQ的神秘面纱。如果你是一个对编程稍有兴趣,但又对消息中间件一知半解的小白,不要害怕,我将用最简单、最友好的语言为你呈…

Linux——命名管道

Linux——命名管道 命名管道命名管道和匿名管道的区别 创建命名管道利用命名管道实现简单通信 我们之前学习了匿名管道,这种管道有一个缺点就是只有两个有血缘关系的进程才能够使用匿名管道,这个非常不方便。所以我们又在匿名管道的基础之上引入了命名管…

Flask python :logging日志功能使用

logging日志的使用 一、了解flask日志1.1、Loggers记录器1.2、Handlers 处理器1.3、Formatters 格式化器 二、使用日志2.1、官网上的一个简单的示例2.2、基本配置2.3、具体使用示例2.4、运行 三、写在最后 一、了解flask日志 日志是一种非常重要的工具,可以帮助开发…

系列学习前端之第 7 章:一文掌握 AJAX

1、AJAX 简介 AJAX 全称为 Asynchronous JavaScript And XML(中文名:阿贾克斯),就是异步的 JS 和 XML。AJAX 不是新的编程语言,而是一种将现有的标准组合在一起使用的新方式。AJAX 可以在浏览器中向服务器发送异步请求…

flutter 弹窗之系列一

自定义不受Navigator影响的弹窗 class MyHomePage extends StatefulWidget {const MyHomePage({super.key, required this.title});final String title;overrideState<MyHomePage> createState() > _MyHomePageState(); }class _MyHomePageState extends State<MyH…

rabbitmq-c 程序实现客户端服务端

安装mq https://blog.csdn.net/zl_momomo/article/details/82986368 需要安裝rabbitmq-server 开启rabbitmq服务 systemctl start rabbitmq-server systemctl enable rabbitmq-server. 客户端 amqp_sendstring.c include <stdint.h> #include <stdio.h> #incl…

访问二维数组本质

先从一维数组讲起 int main() {int arr[5] { 1,2,3,4,5 };for (int i 0; i < 5; i) {printf("%d",arr[i]); //对数组进行访问}return 0; } 其实 arr [ i ] * (arr i) 这两个是完全相等的&#xff0c;在c语言指针&#xff08;1&#xff09;8.数组名与 …

STM32F103 CubeMX 使用USB生成键盘设备

STM32F103 CubeMX 使用USB生成键盘设备 基础信息HID8个数组各自的功能 生成代码代码编写添加申明信息main 函数编写HID 修改1. 修改报文描述符2 修改 "usbd_hid.h" 中的申明文件 基础信息 软件版本&#xff1a; stm32cubmx&#xff1a;6.2 keil 5 硬件&#xff1a;…

Redis中的事件(三)

时间事件 事件的调度与执行 因为服务器中同时存在文件事件和时间事件两种事件类型&#xff0c;所以服务器必须对这两种事件进行调度&#xff0c;决定何时应该处理文件事件&#xff0c;何时有应该处理时间事件&#xff0c;以及花多少事件来处理它们等等。事件的调度和执行由ae…

uniApp中使用小程序XR-Frame创建3D场景(2)加载模型

上篇文章讲述了如何将XR-Frame作为子组件集成到uniApp中使用&#xff0c;只完成了简单的环境搭建&#xff0c;这篇文章讲解如何加载3D模型。 1 加入模型加载标签 在XR-Frame框架中&#xff0c;加载资源都是在wxml文件的标签中实现的。下面是wxml中完整的代码 index.wxml &l…

(二)Eureka服务搭建,服务注册,服务发现

1.Eureka注册中心 假如我们的服务提供者user-service部署了多个实例&#xff0c;如图&#xff1a; 存在几个问题&#xff1a; order-service在发起远程调用的时候&#xff0c;该如何得知user-service实例的ip地址和端口&#xff1f;有多个user-service实例地址&#xff0c;…

手机和键盘的数字键盘排序为什么是不同的?

不知道你有没有注意有一个问题。我们的手机输入法中的数字键盘&#xff0c;电脑上通用的数字键盘&#xff0c;计算器上的数字键盘等排序是不同的&#xff0c;从观察者角度看&#xff0c;0-9的数字排列有从上到下的排列&#xff0c;还有从下到上的排列。为什么会出现不同的排列方…

HWOD:句子逆序

一、题目 描述 将一个英文语句以单词为单位逆序排放。例如I am a boy逆序排放后为boy a am I。所有单词之间用一个空格隔开。语句中除了英文字母外&#xff0c;不再包含其他字符。 数据范围 输入的字符串长度满足 1<n<1000 输入 输入一个英文语句&#xff0c;每个…

【电力监控保护】AM5SE-IS防孤岛保护装置/35kV、10kV、380V分布式光伏并网供电/什么是孤岛效应/孤岛效应的危害

什么是孤岛效应&#xff01;&#xff01;&#xff01; 安科瑞薛瑶瑶18701709087 在电力系统中&#xff0c;孤岛效应指的是当电网突然断电时&#xff0c;并网光伏发电系统仍然保持对电网中部分线路的供电状态。这种情况下&#xff0c;这些线路与其他电网断开&#xff0c;形成了…

HarmonyOS页面布局方式

Column&Row组件的使用 1 概述 一个丰富的页面需要很多组件组成&#xff0c;那么&#xff0c;我们如何才能让这些组件有条不紊地在页面上布局呢&#xff1f;这就需要借助容器组件来实现。 容器组件是一种比较特殊的组件&#xff0c;它可以包含其他的组件&#xff0c;而且…