状态模式

news2024/11/27 0:36:01

文章目录

    • 状态模式
      • 1.状态模式的本质
      • 2.何时选用状态模式
      • 3.优缺点
      • 4.状态模式的结构
      • 5.实现
        • 上下文中维护状态及转换状态
        • 上下文中维护状态处理类中转换状态

状态模式

状态模式说白了就是不同的状态,执行不同的行为,也就是状态和行为分离

1.状态模式的本质

状态模式的本质:根据状态来分离和选择行为。

仔细分析状态模式的结构,如果没有上下文,那么就退化回到只有接口和实现了,正是通过接口,把状态和状态对应的行为分开,才使得通过状态模式设计的程序易于扩展和维护。

而上下文主要负责的是公共的状态驱动,每当状态发生改变的时候,通常都是回调上下文来执行状态对应的功能。当然,上下文自身也可以维护状态的变化,另外,上下文通常还会作为多个状态处理类之间的数据载体,在多个状态处理类之间传递数据。

2.何时选用状态模式

建议在以下情况中选用状态模式。.

  • 如果一个对象的行为取决于它的状态,而且它必须在运行时刻根据状态来改变它的行为,可以使用状态模式,来把状态和行为分离开。虽然分离开了,但状态和行为是有对应关系的,可以在运行期间,通过改变状态,就能够调用到该状态对应的状态处理对象上去,从而改变对象的行为。

  • 如果一个操作中含有庞大的多分支语句,而且这些分支依赖于该对象的状态,可以使用状态模式,把各个分支的处理分散包装到单独的对象处理类中,这样,这些分支对应的对象就可以不依赖于其他对象而独立变化了。

3.优缺点

状态模式有以下优点。

  • 简化应用逻辑控制
    状态模式使用单独的类来封装一个状态的处理。如果把一个大的程序控制分成很多小块,每块定义一个状态来代表,那么就可以把这些逻辑控制的代码分散到很多单独的状态类中去,这样就把着眼点从执行状态提高到整个对象的状态,使得代码结构化和意图更清晰,从而简化应用的逻辑控制。
    对于依赖于状态的if-else,理论上来讲,也可以改变成应用状态模式来实现,把每个if 或else块定义一个状态来代表,那么就可以把块内的功能代码移动到状态处理类中,从而减少if-else,避免出现巨大的条件语句。

  • 更好地分离状态和行为
    状态模式通过设置所有状态类的公共接口,把状态和状态对应的行为分离开,把所有与一个特定的状态相关的行为都放入一个对象中,使得应用程序在控制的时候,只需要关心状态的切换,而不用关心这个状态对应的真正处理。

  • 更好的扩展性
    引入了状态处理的公共接口后,使得扩展新的状态变得非常容易,只需要新增加一个实现状态处理的公共接口的实现类,然后在进行状态维护的地方,设置状态变化到这个新的状态即可。

  • 显式化进行状态转换
    状态模式为不同的状态引入独立的对象,使得状态的转换变得更加明确。而且状态对象可以保证上下文不会发生内部状态不一致的情况,因为上下文中只有一个变量来记录状态对象,只要为这一个变量赋值就可以了。

状态模式也有一个很明显的缺点,一个状态对应一个状态处理类,会使得程序引入太多的状态类,这样程序变得杂乱。

4.状态模式的结构

在这里插入图片描述

  • Context:环境,也称上下文,通常用来定义客户感兴趣的接口,同时维护一个来具体处理当前状态的实例对象。
  • State:状态接口,用来封装与上下文的一个特定状态所对应的行为。
  • ConcreteState:具体实现状态处理的类,每个类实现一个跟上下文相关的状态的具体处理。

5.实现

上下文中维护状态及转换状态

这里用一个借钱的例子:

  • 借钱3次以下:对方会告诉你没钱
  • 借钱3次-5次:对方不回你消息
  • 借钱5次以上:对方拉黑你

在这里插入图片描述

借钱接口及其实现

/**
 * @description:借钱状态接口
 */
public interface BorrowState {

    /**
     * 借钱
     * @param user 用户
     * @param stateManager 状态管理器
     */
    void borrowMoney(String user,StateManager stateManager);
}

/**
 * @description:正常借钱(3次以下)
 */
public class NormalBorrowState implements BorrowState{
    @Override
    public void borrowMoney(String user,StateManager stateManager) {
        System.out.println("对方也没钱啊-,-");
    }
}

/**
 * @description:重复借钱(3-5次)
 */
public class RepeatBorrowState implements BorrowState{
    @Override
    public void borrowMoney(String user,StateManager stateManager) {
        System.out.println("对方表示不想回你消息了-,-");
    }
}

/**
 * @description:恶意借钱(5次以上)
 */
public class BlackBorrowState implements BorrowState{
    @Override
    public void borrowMoney(String user,StateManager stateManager) {
        System.out.println("您已被对方拉黑-,-");
    }
}

状态管理器

/**
 * @description:状态管理器(context)
 */
public class StateManager {

    private BorrowState borrowState;

    //用户,借钱次数
    private Map<String, Integer> countMap = new HashMap<>();

    public void borrow(String user) {
        Integer count = countMap.get(user);
        if (count == null) {
            count = 0;
        }
        //次数+1
        count++;
        countMap.put(user, count);
        //先判断当前状态,根据状态转换不同的行为
        if (count >= 1 && count < 3) {
            borrowState = new NormalBorrowState();
        } else if (count >= 3 && count < 5) {
            borrowState = new RepeatBorrowState();
        } else if (count >= 5) {
            borrowState = new BlackBorrowState();
        }

        this.borrowState.borrowMoney(user, this);
    }
}

测试类

public class Client {

    public static void main(String[] args) {
        StateManager stateManager = new StateManager();
        for (int i = 0; i < 10; i++) {
            stateManager.borrow("张三");
        }
    }
}

结果
在这里插入图片描述

上下文中维护状态处理类中转换状态

借钱接口没变,修改其实现类

/**
 * @description:正常借钱(3次以下)
 */
public class NormalBorrowState implements BorrowState {
    @Override
    public void borrowMoney(String user, StateManager stateManager) {
        System.out.println("对方也没钱啊-,-");
        //取出状态,根据状态转换行为
        Integer count = stateManager.getCountMap().get(user);
        if (count >= 2 && count < 5) {
            stateManager.getStateMap().put(user, new RepeatBorrowState());
        }
    }
}

/**
 * @description:重复借钱(3-5次)
 */
public class RepeatBorrowState implements BorrowState{
    @Override
    public void borrowMoney(String user,StateManager stateManager) {
        System.out.println("对方表示不想回你消息了-,-");
        Integer count = stateManager.getCountMap().get(user);
        if (count >= 5) {
            stateManager.getStateMap().put(user, new BlackBorrowState());
        }
    }
}

/**
 * @description:恶意借钱(5次以上)
 */
public class BlackBorrowState implements BorrowState{
    @Override
    public void borrowMoney(String user,StateManager stateManager) {
        System.out.println("您已被对方拉黑-,-");
    }
}

状态管理器

/**
 * @description:状态管理器(context)
 */
@Getter
public class StateManager {

    //用户,借钱次数
    private Map<String, Integer> countMap = new HashMap<>();
    //用户,要执行的行为
    private Map<String, BorrowState> stateMap = new HashMap<>();

    public void borrow(String user) {
        Integer count = countMap.get(user);
        if (count == null) {
            count = 0;
        }
        //次数+1
        count++;
        //放入状态
        countMap.put(user, count);

        //取出行为
        BorrowState borrowState = stateMap.get(user);
        if (borrowState == null) {
            borrowState = new NormalBorrowState();
        }

        borrowState.borrowMoney(user, this);
    }
}

测试类

public class Client {

    public static void main(String[] args) {
        StateManager stateManager = new StateManager();
        for (int i = 0; i < 10; i++) {
            stateManager.borrow("张三");
        }
    }
}

结果
在这里插入图片描述

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

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

相关文章

Eclipse+Java+Swing+Mysql实现自助存取款机(ATM)系统

EclipseJavaSwingMysql实现自助存取款机ATM系统一、系统介绍1.系统功能2.环境配置3.数据库4.工程截图二、系统展示1.登录页1.1登录成功2.注册系统3.取款3.1取款成功4.存款4.1 存款成功5.转账6.余额查询7.退出系统三、部分代码DBUtil.javaLoginFrame.javaAccount.java四、其他获…

python编程 for循环注意点与大写转换案例

作者简介&#xff1a;一名在校计算机学生、每天分享Python的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 range方法 一for循环表达式 for循环表达式 与数字有关 与单位有关 前言…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java基于信息安全的无锡旅游服务系统5l83d

面对老师五花八门的设计要求&#xff0c;首先自己要明确好自己的题目方向&#xff0c;并且与老师多多沟通&#xff0c;用什么编程语言&#xff0c;使用到什么数据库&#xff0c;确定好了&#xff0c;在开始着手毕业设计。 1&#xff1a;选择课题的第一选择就是尽量选择指导老师…

MHA的故障切换你掌握了吗?

MHA的概述 什么是MHA MHA&#xff08;MasterHigh Availability&#xff09;是一套优秀的MySQL高可用环境下故障切换和主从复制的软件。 MHA 的出现就是解决MySQL 单点的问题。 MySQL故障切换过程中&#xff0c;MHA能做到0-30秒内自动完成故障切换操作。 MHA能在故障切换的过程…

用Python构建Amazon产品推荐系统!这项目价值能有2000吗?

引言 该项目的目标是部分重建Amazon电子类产品的推荐系统。 现在是十二月&#xff01;你是什么类型的购物者&#xff1f;双十二都购买了吗&#xff1f;你是把当天想购买的所有产品都保存起来&#xff0c;还是宁愿打开网站&#xff0c;查看带有巨大折扣的现场优惠呢&#xff1…

从单服务器模式到负载均衡设计

从单服务器模式到负载均衡设计 作者&#xff1a;Grey 原文地址&#xff1a; 博客园&#xff1a;从单服务器模式到负载均衡设计 CSDN&#xff1a;从单服务器模式到负载均衡设计 单服务器模型是最简单的一种架构&#xff0c;参考如下图 用户访问一个 URL&#xff0c;URL 会…

java计算机毕业设计基于安卓Android的校园外卖点餐APP

项目介绍 餐饮行业是一个传统的行业。根据当前发展现状,网络信息时代的全面普及,餐饮行业也在发生着变化,单就点餐这一方面,利用手机点单正在逐步进入人们的生活。传统的点餐方式,不仅会耗费大量的人力、时间,有时候还会出错。Android系统伴随智能手机为我们提供了新的方向。手…

基于转换器 (MMC) 技术和电压源转换器 (VSC) 的高压直流 (HVDC) 模型(MatlabSimulink实现)

目录 1 概述 2 主要模块说明 2.1 简化电网 2.2 转换器 1 2.3 直流电路 2.4 控制器 2.5 示波器和测量 3 讲解 3.1 参数设置 3.2 SPS 比较 3.3 结果比较 3.4 参考文献 4 Matlab代码实现 1 概述 1000 MW HVDC-MMC 互连的 SPS 模型。本文基于模块化多电平转换器 (MMC)…

计算机网络-数据链路层:以太网协议、ARP协议、MAC、MTU

目录 一、以太网协议 1. 认识以太网 2. 协议格式 二、 MAC地址 1. 认识MAC地址 2. 对比MAC地址与IP地址 三、ARP协议 1. 认识ARP协议 2. ARP协议的作用 3. ARP协议的工作流程 4. ARP欺骗攻击 四、MTU 1. 认识MTU 2. MTU对IP协议的影响&#xff08;了解&#xff…

在线教育系统源码讲解与代码分析

目前&#xff0c;许多行业已经开始向直播领域靠拢&#xff0c;例如直播带货、教育直播、娱乐直播等领域&#xff0c;想要在此分一杯羹&#xff0c;以在线教育系统来说&#xff0c;在2020年以后便进入了“白热化”&#xff0c;更多的直播、教育展现在大众视野中。在粉丝经济的时…

Linux的进程空间管理

用户态和内核态的划分 进程的虚拟地址空间&#xff0c;其实就是站在项目组的角度来看内存&#xff0c;所以我们就从task_struct出发来看。这里面有一个struct mm_struct结构来管理内存。 struct mm_struct *mm; 在struct mm_struct里面&#xff0c;有这样一个成员变量&#…

如何利用ArcGIS实现电子地图可视化表达?分析空间数据?提升SCI论文的层次?探究环境与生态因子对水体、土壤、大气污染物等影响?

查看原文>>>如何利用ArcGIS探究环境与生态因子对水体、土壤、大气污染物等影响 如何利用ArcGIS实现电子地图可视化表达&#xff1f;如何利用ArcGIS分析空间数据&#xff1f;如何利用ArcGIS提升SCI论文的层次&#xff1f;制图是地理数据展现的直观形式&#xff0c;也是…

ARM存储模型(数据存储、指令存储)

目录 1、ARM数据存储 (1) ARM数据类型 (2) ARM数据存储的方式 2、ARM的指令存储 (1) 指令集的分类 (2) 为什么ARM指令集的PC值与低2位无关&#xff1f; 1、ARM数据存储 (1) ARM数据类型 ARM采用32位架构&#xff0c;即ARM一次可以处理32bit的数据&#xff0c;基本的数据…

Linux--进程间通信(2)--共享内存--1126

1.共享内存的原理 进程A先申请一段内存空间&#xff0c;其页表映射到物理空间&#xff0c;进程B通过A的页表映射&#xff0c;将B的页表也同样映射到同一块物理空间。 释放共享内存 各自修改各自的页表指向并释放共享内存 2.共享内存的建立过程 头文件 comm.hpp #pragma o…

Windows系统dos命令之cmd

目录1. 使用cd命令快速切换到指定的盘符中1.1 参数说明1.2 cd 切换盘符2. 使用cd命令切换到指定的目录中2.1 切换指定目录3. 使用cd命令退回到上一层目录3.1 使用命令 ”cd ..“4. 使用cd命令直接退回到当前根目录下4.1 使用命令cd \1. 使用cd命令快速切换到指定的盘符中 cd 是…

JUC并发编程第十一篇,Java对象的内存布局

JUC并发编程第十一篇&#xff0c;Java对象的内存布局一、对象在堆内存中的存储布局1、对象头对象标记Mark Word类元信息&#xff08;类型指针&#xff09;2、实例数据3、对齐填充二、对象标记&#xff08;MarkWord&#xff09;布局与验证代码验证&#xff08;JOL&#xff09;一…

重点| 系统集成项目管理工程师考前50个知识点(4)

本文章总结了系统集成项目管理工程师考试背记50个知识点&#xff01;&#xff01;&#xff01; 帮助大家更好的复习&#xff0c;希望能对大家有所帮助 比较长&#xff0c;放了部分&#xff0c;需要可私信&#xff01;&#xff01; 26、编制范围管理计划的输出&#xff1a; 范…

Flink Window Function

窗口函数定义了要对窗口中收集的数据做的计算操作&#xff0c;根据处理的方式可以分为两类&#xff1a;增量聚合函数和全窗口函数。 文章目录1.增量聚合函数1.1 ReduceFunction1.2 AggregateFunction2.全窗口函数2.1 WindowFunction2.2 ProcessWindowFunction3.增量聚合和全窗口…

【MySQL】用户管理

文章目录用户管理用户信息创建用户删除用户修改用户密码用户权限用户赋权回收权限用户管理 如果我们只能使用root用户,这样存在安全隐患,因为root可以访问所有的数据库和表,这时,就需要使用MySQL的用户管理,从而限制某个特定的用户只能访问特定的数据库和表,并且对其权限作出一…

【51-订单模块-资源整合-整合SpringSession-订单中心核心逻辑-认证拦截-订单提交-订单生成逻辑-接口幂等性处理-接口幂等性解决方案】

一.知识回顾 【0.三高商城系统的专题专栏都帮你整理好了&#xff0c;请点击这里&#xff01;】 【1-系统架构演进过程】 【2-微服务系统架构需求】 【3-高性能、高并发、高可用的三高商城系统项目介绍】 【4-Linux云服务器上安装Docker】 【5-Docker安装部署MySQL和Redis服务】…