设计模式: 行为型之中状态模式(20)

状态模式概述

  • 状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为
  • 状态模式通过为每个状态定义一个类,使得对象在其内部状态改变时,可以改变其行为

状态模式应用

// 定义状态接口
interface State {handle(context: Context): void;
}// 定义上下文类
class Context {private currentState: State;constructor(initialState: State) {this.currentState = initialState;}public setState(state: State): void {this.currentState = state;}public request(): void {this.currentState.handle(this);}
}// 创建具体状态类
class ConcreteStateA implements State {handle(context: Context): void {console.log('Handling in ConcreteStateA');// 根据业务逻辑决定切换状态context.setState(new ConcreteStateB());}
}class ConcreteStateB implements State {handle(context: Context): void {console.log('Handling in ConcreteStateB');// 根据业务逻辑决定切换状态context.setState(new ConcreteStateA());}
}// 使用示例
function main() {const context = new Context(new ConcreteStateA());context.request(); // 输出:Handling in ConcreteStateAcontext.request(); // 输出:Handling in ConcreteStateBcontext.request(); // 输出:Handling in ConcreteStateA
}main();
  • 在上述示例中,实现了一个简单的状态模式,模拟了一个根据内部状态变化而改变自身行为的系统
  • 首先,我们定义了一个 State 接口,它要求所有的状态类必须实现一个 handle 方法
  • 这个方法接受一个 Context 参数,当状态发生变化时,handle 方法将被执行,并且可以改变上下文对象的当前状态
  • 然后,我们创建了一个 Context 类,它拥有一个私有变量 currentState 来保存当前的状态对象,并提供 setState 方法来改变当前状态,以及一个 request 方法来触发状态处理
  • 当调用 request 方法时,它会调用当前状态对象的 handle 方法
  • 接下来,我们创建了两个实现了 State 接口的具体状态类:ConcreteStateAConcreteStateB
  • 每个状态类的 handle 方法中根据业务逻辑处理当前请求,并可能通过调用 context.setState 方法改变上下文的当前状态
  • 最后,我们通过一个 main 函数展示了如何使用状态模式
  • 创建了一个 Context 对象并初始化为 ConcreteStateA,然后连续三次调用 request 方法
  • 每次调用都会依据当前状态对象的 handle 方法来处理请求,并在处理过程中切换状态
  • 这个示例展示了状态模式的核心概念,即根据内部状态的不同,对象可以有不同的行为表现
  • 在这种情况下,每次请求都会引发状态的切换,并执行新的状态对象所定义的行为
  • 这个示例展示了状态模式的核心概念,即根据内部状态的不同,对象可以有不同的行为表现
  • 在这种情况下,每次请求都会引发状态的切换,并执行新的状态对象所定义的行为

状态模式与状态机(State Machine)有着密切的关系

  • 状态模式是一种面向对象的设计模式,它将对象的状态和行为分离,使得对象在不同的状态下表现出不同的行为
  • 状态模式的关键在于,每个状态都对应一个类,类中包含了状态转换的逻辑
  • 状态机(Finite State Machine, FSM) 是一种理论模型,描述了一个系统如何根据输入和当前状态转换到下一个状态
  • 状态机包括状态、事件和状态转移函数三个基本要素
  • 状态模式是实现状态机的一种方式,它通过类的实例来表示状态,通过上下文对象来触发状态之间的转换
  • 在上述示例中,Context 类相当于状态机中的主体,其内部维护了当前的状态
  • State 接口以及 ConcreteStateA 和 ConcreteStateB 类则分别代表状态机中的不同状态,它们包含处理请求的方法,并在内部决定了何时以及如何进行状态转换
  • 通过这种方式,状态模式实现了状态机的功能,使得状态切换和行为变化变得清晰且易于维护
  • 状态模式是实现状态机概念的一种方式,它将状态机的理论应用到了面向对象编程的实际设计中
  • 严格来说,状态模式与状态机不是同一回事,但它们密切相关,可以认为状态模式是在软件设计中对状态机概念的具体实现
  • 所以,更精确的说法应该是:“状态模式是对状态机概念的一种实现方式”

状态模式的优缺点


1 ) 优点

  • 封装转换规则:状态模式将状态的转换逻辑封装在状态类中,使得状态变化更加清晰和可维护
  • 扩展性良好:通过引入新的具体状态类,可以方便地扩展系统的功能,满足开闭原则,即在不修改上下文类代码的情况下增加新的状态类
  • 提高可读性:状态模式将状态的判断逻辑分散到具体状态类中,避免了大量的条件语句,使得代码更加清晰和易于理解
  • 减少对象数量:状态模式允许多个环境对象共享一个状态对象,从而减少了系统中对象的个数,提高了资源利用效率

2 )缺点

  • 增加系统复杂性:状态模式引入了多个状态类,可能导致系统的复杂性增加,尤其是在状态转换逻辑复杂的情况下
  • 状态转换逻辑不清晰:如果状态转换的逻辑不够清晰,可能会导致状态切换的错误或不完整,增加了出错的可能性
  • 开闭原则支持不够:虽然状态模式在一定程度上支持开闭原则,但增加新的状态类时可能需要修改负责状态转换的源代码,否则无法切换到新增状态
  • 可能导致代码混乱:状态模式的结构与实现都较为复杂,如果使用不当,可能导致程序结构和代码的混乱,增加系统设计的难度

3 )总结

  • 因此,在使用状态模式时,需要根据具体的应用场景来评估其适用性
  • 在状态变化较为简单且有限的情况下,可能不需要引入状态模式
  • 而在状态变化复杂且需要灵活扩展的情况下,状态模式可以提供一种清晰和可维护的设计方案

状态模式和备忘录模式的区别和联系

  • 状态模式和备忘录模式都是面向对象设计中的重要模式
  • 它们在处理对象的状态和行为方面各有特色,但也存在一些联系

1 )区别

  • 关注点不同:

    • 状态模式关注的是对象在其内部状态改变时行为的改变
    • 它允许对象根据当前状态来改变其行为,使得对象的行为与其状态紧密绑定
    • 而备忘录模式则关注的是在不破坏封装性的前提下
    • 捕获并保存一个对象的内部状态,以便以后能将对象恢复到该状态
    • 它提供了一种机制,使得用户能够撤销操作或恢复数据到之前的状态
  • 应用场景不同

    • 状态模式常用于一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为的情况
    • 例如,一个订单系统,订单的状态可能是待支付、已支付、已发货等,不同的状态下订单的处理逻辑是不同的
    • 而备忘录模式则常用于需要保存对象状态以便后续恢复的场景,如撤销操作、游戏存档等

2 )联系

  • 虽然状态模式和备忘录模式在关注点和应用场景上有所不同,但它们都涉及到对象的状态管理
  • 在某些复杂的系统中,这两种模式可能会结合使用,以更好地管理对象的状态和行为
  • 例如,在一个复杂的游戏系统中
    • 角色可能具有多种状态,如空闲、移动、攻击等,每种状态下角色的行为都有所不同
    • 这可以通过状态模式来实现。同时,为了支持玩家的撤销操作或存档功能
    • 可能需要使用备忘录模式来保存角色在某个时刻的状态
    • 这样,当玩家需要撤销某个操作或恢复存档时,系统可以利用备忘录模式保存的状态信息
    • 将角色恢复到之前的状态

3 )总结

  • 因此,可以说状态模式和备忘录模式在对象状态管理方面具有一定的联系
  • 它们可以结合使用,以提供更强大和灵活的状态管理功能
  • 需要注意的是,具体是否使用这两种模式,以及如何使用
  • 还需要根据具体的业务需求和设计目标来决定
  • 在实际应用中,应根据具体情况权衡利弊,选择最适合的模式或模式组合

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

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

相关文章

小红书2020校招算法笔试题卷一 编程题no.3 击败魔物

题目 击败魔物 薯队长来到了迷宫的尽头,面前出现了N只魔物,Hi表示第i只魔物的血量,薯队长需要在T个回合内击败所有魔物才能获胜。每个回合薯队长可 以选择物理攻击一只魔物,对其造成1点伤害(物理攻击次数无上限&#x…

【ctf.show】获得百分之百的快乐

1.打开靶场 2.根据页面代码,get请求值只能小于4位数,否则会回显hack! 尝试后确实是这样的: 请求值小于4位数,页面无变化: 发送请求值ls查看内容 3.根据2返回的值,发送值为?1>nl 创建一个nl…

vivado 使用基本触发器模式

使用基本触发器模式 基本触发器模式用于描述触发条件 , 即由参与其中的调试探针比较器组成的全局布尔公式。当“触发器模式 (Trigger Mode) ”设置为 BASIC_ONLY 或 BASIC_OR_TRIG_IN 时 , 即启用基本触发器模式。使用“基本触发器设置 (Basic Trig…

Mysql 常用关键字总结

MySQL关键字是指在MySQL中具有特殊含义和功能的保留字。以下是一些常用的MySQL关键字及其作用: 1. SELECT:用于从数据库中检索数据。 2. INSERT:用于向数据库中插入新的行。 3. UPDATE:用于更新数据库中的现有数据。 4. DELETE&a…

【面试题】细说mysql中的各种锁

前言 作为一名IT从业人员,无论你是开发,测试还是运维,在面试的过程中,我们经常会被数据库,数据库中最经常被问到就是MySql。当面试官问MySql的时候经常会问道一个问题,”MySQL中有哪些锁?“当我…

数据结构-----Lambda表达式

文章目录 1 背景1.1 Lambda表达式的语法1.2 函数式接口 2 Lambda表达式的基本使用2.1 语法精简 3 变量捕获3.1 匿名内部类3.2 匿名内部类的变量捕获3.3 Lambda的变量捕获 4 Lambda在集合当中的使用4.1 Collection接口4.2 List接口4.3 Map接口 HashMap 的 forEach() 5 总结 1 背…

第十三届蓝桥杯真题:x进制减法,数组切分,gcd,青蛙过河

目录 x进制减法 数组切分 gcd 青蛙过河 x进制减法 其实就是一道观察规律的题。你发现如果a这个位置上的数x&#xff0c;b这个位置上的数是y&#xff0c;那么此位置至少是max(x,y)1进制。一定要把位置找对啊 #include <bits/stdc.h> using namespace std; typedef l…

蓝桥杯20年第十一届国赛-答疑|贪心

题目链接&#xff1a; 蓝桥杯2020年第十一届国赛真题-答疑 - C语言网 (dotcpp.com) 思路&#xff1a; 这道题 计算的是时刻之和&#xff0c;写出这个时刻之和的计算式子&#xff0c;以下的si&#xff0c;ai的i为任意次序答疑的同学编号 &#xff0c;不等于输入的顺序 时刻之…

如何卸载干净 IDEA(图文讲解)

更新时间 2022-12-20 11:一则或许对你有用的小广告 星球 内第一个项目&#xff1a;全栈前后端分离博客项目&#xff0c;演示地址&#xff1a;Weblog 前后端分离博客, 1.0 版本已经更新完毕&#xff0c;正在更新 2.0 版本。采用技术栈 Spring Boot Mybatis Plus Vue 3.x Vit…

没有网没有移动存储的情况下两台电脑如何互相传输数据

无网无移动存储情况下两台电脑数据互传探秘 一、直连网线传输数据二、局域网文件共享其他 在信息化时代的今天&#xff0c;电脑作为重要的数据处理工具&#xff0c;在日常生活和工作中扮演着不可或缺的角色。然而&#xff0c;有时我们会遇到一些特殊情况&#xff0c;如没有网络…

如何开辟动态二维数组(C语言)

1. 开辟动态二维数组 C语言标准库中并没有可以直接开辟动态二维数组的函数&#xff0c;但我们可以通过动态一维数组来模拟动态二维数组。 二维数组其实可以看作是一个存着"DataType []"类型数据的一维数组&#xff0c;也就是存放着一维数组地址的一维数组。 所以&…

DOTS Unity.Physics物理引擎碰撞事件处理

最近DOTS发布了正式的版本,同时基于DOTS的理念实现了一套高性能的物理引擎&#xff0c;今天我们给大家分享和介绍一下这个物理引擎的碰撞事件处理以及核心相关概念。 Unity.Physics物理引擎的主要流程与Pipeline Unity.Physics物理引擎做仿真迭代计算的时候主要通过以下步骤来…

【C++成长记】C++入门 | 命名空间、输入输出、缺省参数

&#x1f40c;博主主页&#xff1a;&#x1f40c;​倔强的大蜗牛&#x1f40c;​ &#x1f4da;专栏分类&#xff1a;C​​​​​​​❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、C和C语言的区别和联系 二、命名空间 1、命名空间定义 2、命名空间使用 三、C输…

基于yolov9来训练人脸检测

YOLOv9是一个在目标检测领域内具有突破性进展的深度学习模型&#xff0c;尤其以其在实时性与准确性上的优秀表现而受到广泛关注。针对人脸检测这一特定任务&#xff0c;YOLOv9通过其架构创新和算法优化提供了强大的支持。 YOLOv9在继承了YOLO系列&#xff08;如YOLOv7、YOLOv8&…

二叉树--相同的树

给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例 1&#xff1a; 输入&#xff1a;p [1,2,3], q [1,2,3] 输出&#xff1a;true 思路 一、…

90天玩转Python—14—基础知识篇:变量进阶

90天玩转Python系列文章目录 90天玩转Python—01—基础知识篇:C站最全Python标准库总结 90天玩转Python--02--基础知识篇:初识Python与PyCharm 90天玩转Python—03—基础知识篇:Python和PyCharm(语言特点、学习方法、工具安装) 90天玩转Python—04—基础知识篇:Pytho…

JavaEE 初阶篇-深入了解 CAS 机制与12种锁的特征(如乐观锁和悲观锁、轻量级锁与重量级锁、自旋锁与挂起等待锁、可重入锁与不可重入锁等等)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 乐观锁与悲观锁概述 1.1 悲观锁&#xff08;Pessimistic Locking&#xff09; 1.2 乐观锁&#xff08;Optimistic Locking&#xff09; 1.3 区别与适用场景 2.0 轻…

C++高级特性:柯里化过程与std::bind(六)

1、柯里化过程 1.1、operator()的引入 现在需要完成这样一个需求&#xff1a;有一个函数每次调用返回的结果不一样。例如&#xff1a;两次调用的返回值都不一样那么就可以达到这种目的 1.1.1、简单点的写法 可以给一个全局的变量&#xff08;静态变量&#xff09;&#xff…

java项目两种方法实现大批量数据:存在就更新,不存在就新增,脏数据就删除。

java项目两种方法实现大批量数据&#xff1a;存在就更新&#xff0c;不存在就新增&#xff0c;脏数据就删除。 文章目录 java项目两种方法实现大批量数据&#xff1a;存在就更新&#xff0c;不存在就新增&#xff0c;脏数据就删除。一、法一&#xff1a;存在就更新&#xff0c;…

Docker 安装Kali Linux作为攻防演练的工具

使用Docker Compose安装和运行Kali Linux是一种简便且灵活的方式&#xff0c;特别适合那些希望在隔离环境中快速部署和管理多个Docker容器的用户。以下是详细的步骤&#xff0c;包括如何设置Docker Compose文件来运行Kali Linux&#xff1a; 步骤 1: 安装Docker 如果你的系统…