软件设计模式系列之二十二——状态模式

news2024/11/25 22:36:03

1 模式的定义

状态模式是一种行为型设计模式,它允许对象在内部状态发生改变时改变其行为,使得对象的行为看起来像是改变了其类。状态模式将对象的状态抽象成一个独立的类,让对象在不同状态下具有不同的行为,而且可以在运行时切换状态。这种方式使得状态的管理更加清晰,避免了大量的条件判断语句,提高了代码的可维护性和可扩展性。

2 举例说明

在日常生活中,有许多符合状态模式并为大家所熟知的例子。以下是几个常见的例子:

交通信号灯。
交通信号灯是一个典型的状态模式的例子。它有三种状态:红灯、绿灯和黄灯。每种状态都对应着不同的行为,如红灯停、绿灯行、黄灯准备停等。信号灯在不同状态之间切换,根据交通需求控制交通流量。
在这里插入图片描述

游戏角色状态。
在电子游戏中,游戏角色通常有多种状态,如站立、行走、奔跑、攻击等。玩家通过控制输入来改变游戏角色的状态,从而实现不同的行为。

自动售货机。
自动售货机也是一个状态模式的例子。它通常有多个状态,如空闲、接受货币、选择商品、出货等。售货机会根据用户的操作和投入的货币来改变状态,最终完成购买过程。

这些例子都展示了状态模式在日常生活中的广泛应用。它们通过将对象的状态抽象成不同的类,并根据当前状态执行相应的行为,实现了状态和行为的解耦,提高了系统的灵活性和可维护性。

3 结构

状态模式的主要结构包括以下几个角色:
在这里插入图片描述

Context(上下文):维护一个对具体状态对象的引用,负责将客户端的请求委派给当前状态对象处理。

State(状态抽象类或接口):定义一个接口或抽象类,用于封装与Context相关的一个或多个行为。

ConcreteState(具体状态类):实现State接口或继承State抽象类,具体实现状态相关的行为。

Client(客户端):使用Context来与状态对象进行交互,不直接与具体状态类交互。

4 实现步骤

实现状态模式的关键步骤如下:

定义状态抽象类或接口(State),声明状态相关的方法。

创建具体状态类,实现状态抽象类或接口中的方法,每个具体状态类代表一个状态。

创建上下文类(Context),维护一个对当前状态对象的引用,并将请求委派给当前状态对象处理。

在客户端中创建上下文对象,通过上下文对象来与状态对象交互。

5 代码实现(Java)

下面是一个简单的状态模式的Java示例,实现一个电梯控制系统:

// 步骤1: 定义状态抽象类
interface State {
    void open();
    void close();
    void run();
    void stop();
}

// 步骤2: 创建具体状态类
class OpenState implements State {
    // 实现状态相关的方法
    // ...
}

class CloseState implements State {
    // 实现状态相关的方法
    // ...
}

class RunState implements State {
    // 实现状态相关的方法
    // ...
}

class StopState implements State {
    // 实现状态相关的方法
    // ...
}

// 步骤3: 创建上下文类
class Context {
    private State currentState;

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

    public void request() {
        currentState.handle();
    }
}

// 步骤4: 在客户端中使用状态模式
public class Client {
    public static void main(String[] args) {
        Context context = new Context();
        context.setState(new CloseState());

        // 在不同状态下请求
        context.request();
    }
}

6 典型应用场景

状态模式适用于以下情况:

对象的行为随着其内部状态的改变而改变:如果一个对象有多个状态,且在不同状态下需要不同的行为,状态模式是一个合适的选择。它允许对象在运行时根据其状态切换行为,而无需大量的条件判断语句。

条件语句过多且难以维护:当一个对象有多个状态,并且在不同状态下需要执行不同的操作时,通常会导致大量的条件语句。状态模式能够将这些条件逻辑封装在不同的状态类中,使得代码更加清晰、可维护,并降低错误的风险。

状态转换需要动态性:如果状态之间的转换规则需要在运行时动态改变,状态模式可以灵活应对这种需求。状态模式使得状态切换变得容易,可以根据特定条件自动切换状态。

对象的状态会频繁变化:如果对象的状态会频繁发生改变,使用状态模式可以简化状态管理,并且使得状态变化对系统的影响更加可控。

需要避免使用大量条件判断语句:状态模式能够避免大量的条件判断语句,提高代码的可读性和可维护性。这对于复杂的状态管理场景特别有用。

对象的行为和状态无法简单映射为枚举类型:有时对象的状态和行为并不容易用简单的枚举类型表示,而是需要更多的灵活性和复杂性。状态模式可以提供这种灵活性。

希望通过组合而不是继承来扩展对象的行为:状态模式是一种对象组合的方式,可以通过组合不同的状态类来扩展对象的行为,而不是通过继承来实现。

总之,状态模式在处理对象的状态和行为之间的复杂关系,以及需要将状态转换逻辑封装、分离和可维护时,是一个非常有用的设计模式。它能够提高代码的可扩展性、可读性和可维护性,尤其在需要处理多个状态和状态之间复杂转换规则的情况下表现出色。

7 优缺点

优点:

将状态相关的行为封装到不同的状态类中,提高了代码的可维护性和可读性。
可以轻松添加新的状态类,扩展系统的行为。
避免了大量的条件判断语句,使得代码更加简洁。

缺点:

如果状态转换逻辑过于复杂,可能会导致类的数量增加,增加维护难度。
不适用于所有情况,只有当对象的行为与其状态密切相关时才适用。

8 类似模式

策略模式(Strategy Pattern):

策略模式和状态模式都允许对象在运行时改变其行为,但它们的目的不同。状态模式关注对象在不同状态下的行为变化,而策略模式关注在相同状态下不同算法的选择。在策略模式中,算法可以随时替换,而在状态模式中,状态会影响对象的行为。电梯控制系统可以使用状态模式来管理电梯状态(停止、上升、下降),而支付系统可以使用策略模式来选择不同的支付策略(信用卡支付、支付宝支付)。

责任链模式(Chain of Responsibility Pattern):

责任链模式和状态模式都可以通过对象之间的协作来处理请求,但它们的目的和结构不同。责任链模式用于处理多个处理器对象,每个处理器可以选择处理请求、传递给下一个处理器或者中断链条。状态模式用于对象状态的管理,每个状态对象负责处理对象在特定状态下的请求。请假申请审批系统可以使用责任链模式,不同级别的审批者可以构成责任链,每个审批者可以选择批准、拒绝或者将请求传递给下一个审批者。在状态模式中,审批状态可以是一种状态。

虽然这些模式有相似之处,但它们在解决不同问题和场景中具有不同的应用。选择合适的模式取决于问题的性质和需求。

9 小结

状态模式是一种强大的设计模式,用于管理对象的状态和行为,使得系统更加灵活和可扩展。通过将状态抽象成独立的类,状态模式消除了大量的条件判断,使得代码更加清晰易懂。在实际应用中,状态模式可以帮助我们构建更加可维护和可扩展的系统,提高代码质量和可读性。无论是电梯控制系统还是订单状态管理,状态模式都可以发挥其优势,让软件设计更加优雅和灵活。希望本文能够帮助读者深入理解状态模式,并在实际项目中灵活运用。

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

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

相关文章

做一个优秀的博士生,时间的付出是必要条件

*图片来自管理学季刊 时间的付出 所有成功的科学家一定具有的共同点,就是他们必须付出大量的时间和心血。这是一条真理。实际上,无论社会上哪一种职业,要想成为本行业中的佼佼者,都必须付出比常人多的时间。有时&…

【知识点随笔分析 | 第六篇】HTTP/1.1,HTTP/2和HTTP/3的区别

前言: 当今互联网已成为人们生活的重要组成部分,而HTTP协议(Hypertext Transfer Protocol)是支持Web通信的基础。随着Web技术的发展和互联网应用的不断增多,HTTP也在不断演进。本文旨在介绍HTTP的演变过程中的三个重要…

【Godot4.1】Godot实现闪烁效果(Godot使用定时器实现定时触发的效果)

文章目录 准备工作创建Sprite2D创建Timer节点 编写脚本完整代码运行效果 准备工作 如果你希望配置C#编写脚本,可以查看如下教程: Godot配置C#语言编写脚本 创建Sprite2D 首先弄一个用于显示的Sprite2D,右键单击任意节点,然后选…

Transformer在小目标检测上的应用

本篇文章是博主在AI、无人机、强化学习等领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对人工智能等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在AI学…

mysql双主互从通过KeepAlived虚拟IP实现高可用

mysql双主互从通过KeepAlived虚拟IP实现高可用 在mysql 双主互从的基础上, 架构图: Keepalived有两个主要的功能: 提供虚拟IP,实现双机热备通过LVS,实现负载均衡 安装 # 安装 yum -y install keepalived # 卸载 …

反向输出一个三位数

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…

手把手教你完成(Java)师生信息管理系统

手把手教你完成(Java)师生信息管理系统 对阶段一学到的知识进行应用,完成练手小项目。同时,也可以当做学校的课设来做。项目已上传 CSDN ,可以按需下载。 一、成果展示 添加学生(查看学生) 删除…

计算机毕业设计 基于SSM的宿舍管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

【C进阶】指针笔试题解析

做题之前我们再来回顾一下 对于数组名的理解:除了以下两种情况,数组名表示的都是数组首元素的地址 (1)sizeof(数组名):这里的数组名表示整个数组 (2)&(数…

关掉在vscode使用copilot时的提示音

1. 按照图示的操作File --> Preferences --> Settings 2. 搜索框输入关键字Sound,因为是要关掉声音,所以找有关声音的设置 3. 找到如下图所示的选项 Audio Cues:Line Has Inline Suggetion,将其设置为Off 这样,就可以关掉suggest code时…

使用 Python 给 PDF 添加目录书签

0、库的选择——pypdf 原因:Python Version Support Python 3.11 3.10 3.9 3.8 3.7 3.6 2.7 pypdf>3.0 YES YES YES YES YES YES PyPDF2>2.0 YES YES YES YES YES YES PyPDF2 1.20.0 - 1.28.4 YES YES YES YES YES YES P…

【JAVA】为什么要使用封装以及如何封装

个人主页:【😊个人主页】 系列专栏:【❤️初识JAVA】 前言 Java的封装指的是在一个类中将数据和方法进行封装,使其可以保护起来,只能在该类内部访问,而不允许外部直接访问和修改。这是Java面向对象编程的三…

Python3学习笔记——第一章:基础入门

Python3 有段时间没摸Python了,浏览了一下菜鸟教程,巩固一下基础吧。 Python3学习笔记——第一章:基础入门 文章目录 Python3一、Python3 简介二、Python的安装三、查看 Python 版本四、第一个Python3程序 一、Python3 简介 讲几个对编程有…

【Cesium创造属于你的地球】相机系统

相机系统里面有setView,flyTo,lookAt,viewBoundingsphere这几种方法,以下是相关的使用方法,学起来!!! setView 该方法可以直接切换相机视口,从而不需要通过一个飞入的效…

【Java】什么是继承

目录 什么是继承 继承关系图 idea如何生成继承类图 继承优缺点 什么情况下使用继承模式呢? 继承中变量的访问特点 什么是继承 继承是面向对象的三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义、追加属性和方法…

蓝桥杯Python scratch C++选拔赛stema个人如何报名?

如果不会操作,可以微信makytony协助。

阅读LINGO-1: Exploring Natural Language for Autonomous Driving

1 背景2 Motivation3 具体过程 1 背景 wayve在9月14日公布了大语言模型和自动驾驶的结合模型LINGO-1,可以用自然语言解释自动驾驶的决策原因。 网页链接:https://wayve.ai/thinking/lingo-natural-language-autonomous-driving/ 但是目前没有论文和开源…

【牛客网】JZ39 数组中出现次数超过一半的数字

题目 思路 思路1 将数组排序,再保证有结果的情况下,此时数组中间的数字就是想要的结果 思路2 在保证有结果的情况下,此时数组的的众数是数组长度的一半以上 所以我们可以通过抵消的做法来找到最终的结果 我们可以从头遍历这个数组,如果两个数不相同,则消去这两个数,最坏的…

SpringBoot的学习

代码书写:耦合度偏高 解决方法:使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象——IcC控制反转 IoC(Inversion of Control)控制反转 使用对象时,由主动new产生对象转换为…

链式二叉树的基本操作实现

💓博主csdn个人主页:小小unicorn ⏩专栏分类:数据结构 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 链式二叉树基本操作 二叉树节点设置二叉树的深…