详解设计模式:状态模式

news2024/11/17 7:46:26

状态模式(State Pattern)也被称为状态机模式(State Machine Pattern),是在 GoF 23 种设计模式中定义了的行为型模式。

在状态模式 类的行为是基于它的状态改变的。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。状态模式 对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

本篇文章内容包括:关于状态模式、状态模式 Demo


文章目录

    • 一、关于状态模式
        • 1、关于状态模式
        • 2、关于状态模式的构成
        • 3、关于状态模式UML
        • 4、关于状态模式的应用场景
        • 5、关于状态模式的优缺点
    • 二、状态模式 Demo
        • 1、Demo 设计
        • 2、Demo 实现
        • 3、Demo 测试


一、关于状态模式

1、关于状态模式

状态模式(State Pattern)也被称为状态机模式(State Machine Pattern),是在 GoF 23 种设计模式中定义了的行为型模式。

在状态模式 类的行为是基于它的状态改变的。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。状态模式 对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

2、关于状态模式的构成

状态模式主要包含以下 3 种角色:

  • 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换;
  • 抽象状态(State)角色:定义一个接口,用以封装环境中的特定状态所对应的行为,可以有一个或多个行为;
  • 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。

3、关于状态模式UML

image-20221203202933112

4、关于状态模式的应用场景

通常在以下情况下可以考虑使用状态模式。

  • 当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
  • 一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。

5、关于状态模式的优缺点

# 状态模式优点

  • 可以将不同的状态隔离;
  • 每个状态都是一个单独的类;
  • 可以将各种状态的转换逻辑,分布到状态的子类中,减少相互依赖;
  • 增加新状态,操作简单;

# 状态模式缺点

  • 如果状态数量比较多,状态类的数量会增加,业务场景系统变得很复杂;
  • 如果业务中某个对象由几十上百个状态,就会很复杂,这时就需要对状态进行拆分处理。

二、状态模式 Demo

1、Demo 设计

我们此处可以设计一个多线程的状态转换程序,多线程存在 新建、就绪、运行、阻塞和死亡状态。各种状态当遭到相关方法调用/事件触发时会向其他状态转换。

2、Demo 实现

# ThreadContext 环境类(Context)角色

public class ThreadContext {

    private ThreadState state;

    ThreadContext() {
        state = new New();
    }

    public ThreadState getState() {
        return state;
    }

    public void setState(ThreadState state) {
        this.state = state;
    }

    public void start() {
        ((New) state).start(this);
    }

    public void getCpu() {
        ((Runnable) state).getCpu(this);
    }

    public void suspend() {
        ((Running) state).suspend(this);
    }

    public void stop() {
        ((Running) state).stop(this);
    }

    public void resume() {
        ((Blocked) state).resume(this);
    }
}

# ThreadState 抽象状态(State)角色

public abstract class ThreadState {

    /**
     * 状态名
     */
    protected  String stateName;
}

# 新建 New 具体状态(Concrete State)角色

public class New extends ThreadState {

    public New() {
        stateName = "新建";
        System.out.println("线程状态:新建");
    }

    public void start(ThreadContext context) {
        System.out.println("调用 start 方法");
        if ("新建".equals(stateName)) {
            context.setState(new Runnable());
        } else {
            System.out.println("当前线程不是 New 状态,无法调用 start");
        }
    }
}

# 就绪 Runnable 具体状态(Concrete State)角色

public class Runnable extends ThreadState{

    public Runnable() {
        stateName = "就绪";
        System.out.println("线程状态:就绪");
    }

    public void getCpu(ThreadContext context) {
        System.out.println("调用 getCpu 方法");
        if ("就绪".equals(stateName)) {
            context.setState(new Running());
        } else {
            System.out.println("当前线程不是 就素 状态,无法调用获取 '获取CPU' 的方法");
        }
    }
}

# 运行 Running 具体状态(Concrete State)角色

public class Running extends ThreadState {

    public Running() {
        stateName = "运行";
        System.out.println("线程状态:运行");
    }

    /**
     * 挂起
     * @param context ThreadContext
     */
    public void suspend(ThreadContext context) {
        System.out.println("调用 suspend 方法");
        if ("运行".equals(stateName)) {
            context.setState(new Blocked());
        } else {
            System.out.println("当前线程不是 运行 状态,无法调用获取 '挂起' 的方法");
        }
    }

    /**
     * 停止
     * @param context ThreadContext
     */
    public void stop(ThreadContext context) {
        System.out.println("调用 stop 方法");
        if ("运行".equals(stateName)) {
            context.setState(new Dead());
        } else {
            System.out.println("当前线程不是 运行 状态,无法调用获取 '停止' 的方法");
        }
    }
}

# 阻塞 Blocked 具体状态(Concrete State)角色

public class Blocked extends ThreadState {

    public Blocked() {
        stateName = "阻塞";
        System.out.println("线程状态:阻塞");
    }

    /**
     * 状态恢复
     * @param context ThreadContext
     */
    public void resume(ThreadContext context) {
        System.out.println("调用 resume 方法");
        if ("阻塞".equals(stateName)) {
            context.setState(new Runnable());
        } else {
            System.out.println("当前线程不是 阻塞 状态,无法调用获取 '状态恢复' 的方法");
        }
    }
}

# 死亡 Dead 具体状态(Concrete State)角色

public class Dead extends ThreadState {

    public Dead() {
        stateName = "死亡";
        System.out.println("线程状态:死亡");
    }
}

3、Demo 测试

public class Client {

    public static void main(String[] args) {
        ThreadContext context = new ThreadContext();
        context.start();
        context.getCpu();
        context.suspend();
        context.resume();
        context.getCpu();
        context.stop();
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

9.图片分类数据集

1. 图像分类数据集 MNIST数据集 [LeCun et al., 1998] 是图像分类中广泛使用的数据集之一,但作为基准数据集过于简单。 我们将使用类似但更复杂的Fashion-MNIST数据集。 %matplotlib inline import torch import torchvision from torch.utils import data from t…

idea配置tomcat热部署不生效问题

idea中配置了tomcat的“update classes and resources”后,点击run之后,每次修改代码都没有及时生效,也就是没有成功进行热部署。 在idea中实现热部署,要先设置自动编译,再选择正确的运行模式(Debug运行&am…

SSM和SpringBoot整合

目录 一、整合Mybatis 配置文件 pom.xml application.yml jdbc.properties generatorConfig.xml 启动类 测试 二、整合Mybatis-plus Mybatis-plus 新建项目 pom.xml application.yml 在项目导入mybatis-plus的代码生成的类 完成基本增删改查方法开发 三、Mybatispl…

常用数据库之sql server的使用和搭建

1.1 介绍 关系型数据库,SQLServer是由微软公司开发的一种关系型据库管理系统,它已广泛用于电子商务、银行、保险、电力等行业。SQLServer提供了对XML和Internet标准的支持,具有强大的、灵活的、基于Web的应用程序管理功能。 1.2 优缺点 优点…

毕业设计-基于机器视觉的安全帽佩戴识别系统

目录 前言 课题背景与意义 课题实现技术思路 目标检测 算法检测 算法实现 最后 前言 📅大四是整个大学期间最忙碌的时光,一边要忙着准备考研,考公,考教资或者实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越…

企业子网划分详解

一、IP协议 1、IP协议简介 IP协议是TCP/IP协议族的基石,它为上层提供无状态、无连接、不可靠的服务,也是Socket网络编程的基础之一。 IP协议特点: 无状态:指IP通信双方不同步传输数据的状态信息,因此所有IP数据报的发送,传输,接收都是相互独立的。这种服务最大缺点是…

Web5到底是什么?Web4去哪了?

Web3咱还没搞明白,Web3还没有完全的投入应用 ,这Web5怎么就来了? 在今年6月召开的加密盛宴Consensus上,推特创始人比特必信徒杰克多西,首次提出全新Web5的概念,并公开呛声Web3的VC们可以洗洗睡了&#xff…

【Lilishop商城】No2-7.确定软件架构搭建六(本篇包括延时任务,会用到rocketmq、redis)

仅涉及后端,全部目录看顶部专栏,代码、文档、接口路径在: 【Lilishop商城】记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇只介绍重点架构逻辑,具体编写看源代码就行,读起来也不复杂~ 谨慎&#xf…

使用python进行贝叶斯统计分析

本文讲解了使用PyMC3进行基本的贝叶斯统计分析过程. 最近我们被客户要求撰写关于贝叶斯统计分析的研究报告,包括一些图形和统计输出。 # 导入 import pymc3 as pm # python的概率编程包 import numpy.random as npr # numpy是用来做科学计算的 import matplotlib…

cubeIDE开发,结合图片取模工具,stm32程序在LCD显示图片

一、图片取模工具(imag2lcd) 我们前面将汉字显示时说过,嵌入式LCD屏显示就是通过LCD屏幕数据接口给每个屏幕像素给出一个颜色值实现实时渲染显示出来。只不过文字显示时,给出的是一个二进制点阵,然后根据二进制中的“1…

Java文件输入输出(简单易懂版)

文章目录写在前面文件输入文件输出写在前面 在Java中不论文件输入还是输出都会用到File类,参考这篇文章Java File类(文件操作类)详解这里会涉及到绝对路径、相对路径、路径中的斜杠“/”和反斜杠“\”,有些小伙伴可能不熟悉&…

数据结构—B树、B+树

文章目录B树B树的特点为什么要有B树:红黑树和B树比较B树B树的特点B树构建过程查询时数据提供数据磁盘向cpu推送数据B树的优点总结为什么要有B树:B树用途:为什么要有B树:B树用途:———————————————————…

WorkTool企微机器人APP分享自定义小程序

移动端应用怎么分享自定义小程序到企业微信 前言 什么是自定义小程序,就是我们可以通过业务逻辑或代码来动态修改每次发出的小程序所附带的路径(path)和参数(params),以此来控制每次发出的小程序都是有不同含义的,但企业微信并不让我们这样…

[附源码]Python计算机毕业设计Django体育器材及场地管理系统

项目运行 环境配置: Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术: django python Vue 等等组成,B/S模式 pychram管理等等。 环境需要 1.运行环境:最好是python3.7.7,…

【Spring】事务管理

目录项目目录spring-dao.xml测试项目目录 UserMapper.xml写sql语句UserMapperImpl继承sqlSessionDaoSupport然后在里面做一个addUser和一个delete我们delete语句故意写错 但是我们想把add和delete当成一个事务delete错了,add也不应该成功所以我们需要进行事务管理配…

FLStudio2023水果中文版本使用操作心得与技巧

FL Studio2023是一款强大的音乐创作编辑软件,因软件LOGO为水果标志,故我们国人都习惯称之为水果。它让你的计算机就像是全功能的录音室,漂亮的大混音盘,先进的创作工具,让你的音乐突破想象力的限制。因此它又有"水…

手撕ThreadLocal源码

首先&#xff0c;创建MyThreadLocal类&#xff0c;区分开java.lang.ThreadLocal package com.huhu.threadlocal;import java.util.HashMap; import java.util.Map;public class MyThreadLocal<T> {/*** 所有需要和当前线程绑定的数据要放到这个容器当中*/private Map<…

WIFI的传输距离介绍

WIFI的传输距离介绍 WiFi模块在智能家居&#xff0c;智能驾舱等各行业各领域应用极广&#xff0c; 但有多少人了解他的传输距离是多少呢&#xff1f;是受什么影响呢&#xff1f; 一&#xff1a;WiFi模块的传输距离 WiFi模块的传输距离普遍在100-200米之间&#xff0c;其中也有支…

乐观锁思想在JAVA中的实现——CAS

前言 生活中我们看待一个事物总有不同的态度&#xff0c;比如半瓶水&#xff0c;悲观的人会觉得只有半瓶水了&#xff0c;而乐观的人则会认为还有半瓶水呢。很多技术思想往往源于生活&#xff0c;因此在多个线程并发访问数据的时候&#xff0c;有了悲观锁和乐观锁。 悲观锁认…

React+ts学习文档

1.项目中遇到的困难解决以及方案 1.顶部的查询按钮 点击查询如果在该组件去进行axios请求&#xff0c;这样再该组件下获得返回的列表还需要传回父组件&#xff0c;父组件再把列表发给下面的table组件&#xff0c;不太方便。 解决方案&#xff1a;将用户的选择项传给顶级组件i…