【设计模式-4.6】行为型——状态模式

news2025/7/27 4:57:00

说明:本文介绍行为型设计模式之一的状态模式

定义

状态模式(State Pattern)也叫作状态机模式(State Machine Pattern),允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类,属于行为型设计模式。(引自《设计模式就该这样学》P348)

“对象看起来好像修改了它的类”,指对象的状态发生改变后,与之对应的行为也会发生改变(当然,这取决于你的业务逻辑)。


状态模式中类的行为是由状态决定的,在不同的状态下有不同的行为。其意图是让一个对象在其内部改变的时候,行为也随之改变。状态模式的核心是状态与行为绑定,不同的状态对应不同的行为。(引自《设计模式就该这样学》P348)

这段讲的很好。

灯的状态

灯的状态简单来分,只有两种,开的和熄灭的,所以更换灯的状态,代码写出来,很简单,如下:

/**
 * 灯开关
 */
public class Switcher {

    /**
     * 灯状态
     * false:熄灯
     * true:开灯
     */
    private boolean state = false;

    /**
     * 使开灯
     */
    public void switchOn() {
        state = true;
        System.out.println("开灯");
    }

    /**
     * 使熄灯
     */
    public void switchOff() {
        state = false;
        System.out.println("熄灯");
    }
}

作为程序员的严谨,需要考虑到灯在开启的时候,再调用开启方法的情况和灯在熄灭的时候,再调用熄灭方法的情况,如下:

/**
 * 灯开关-Plus
 */
public class SwitcherPlus {

    /**
     * 灯状态
     * false:熄灯
     * true:开灯
     */
    private boolean state = false;

    public void switchOn() {
        // 如果是熄灯
        if (!state) {
            state = true;
            System.out.println("开灯");
        } else {
            System.out.println("灯已经是开灯状态,无需重复开灯");
        }
    }

    public void switchOff() {
        // 如果是开灯
        if (state) {
            state = false;
            System.out.println("熄灯");
        } else {
            System.out.println("灯已经是熄灭状态,无需重复熄灯");
        }
    }
}

代码变得复杂起来了,以上仅是一个对象,两种状态的情况,用if-else还能应付。如果是多个状态,例如交通信号灯,有红黄绿三个状态,绿灯变红灯,红灯变黄灯,黄灯变绿灯,代码如下:

/**
 * 交通信号灯
 */
public class TrafficLight {

    /**
     * 信号灯状态,默认红
     * 红灯转绿灯,绿灯转黄灯,黄灯转红灯
     */
    private String state = "红";

    /**
     * 切换到绿灯
     */
    public void switchToGreen() {
        if ("绿".equals(state)) {
            System.out.println("已是绿灯,无需切换。。。");
        } else if ("红".equals(state)) {
            System.out.println("成功切换到绿灯~~~");
        } else if ("黄".equals(state)) {
            System.out.println("黄灯不能切换到绿灯!!!");
        }
    }

    /**
     * 切换到黄灯
     */
    public void switchToYellow() {
        if ("绿".equals(state)) {
            System.out.println("成功切换到黄灯~~~");
        } else if ("红".equals(state)) {
            System.out.println("红灯不能切换到黄灯!!!");
        } else if ("黄".equals(state)) {
            System.out.println("已是黄灯,无需切换。。。");
        }
    }

    /**
     * 切换到红灯
     */
    public void switchToRed() {
        if ("绿".equals(state)) {
            System.out.println("绿灯不能切换到红灯!!!");
        } else if ("红".equals(state)) {
            System.out.println("已是红灯,无需切换。。。");
        } else if ("黄".equals(state)) {
            System.out.println("成功切换到红灯~~~");
        }
    }
}

多层的if-else,代码显得臃肿,难以维护,后续涉及修改也会频繁改动这个类。

状态模式

使用状态模式,将方法、状态抽出来,如下:

(状态接口,State)

/**
 * 状态
 */
public interface State {

    /**
     * 切换到绿灯
     */
    void switchToGreen(TrafficLight trafficLight);

    /**
     * 切换到黄灯
     */
    void switchToYellow(TrafficLight trafficLight);

    /**
     * 切换到红灯
     */
    void switchToRed(TrafficLight trafficLight);
}

(红灯实现类,Red,注意切换成功后修改状态)

/**
 * 红灯
 */
public class Red implements State {

    @Override
    public void switchToGreen(TrafficLight trafficLight) {
        trafficLight.setState(new Green());
        System.out.println("成功切换到绿灯~~~");
    }

    @Override
    public void switchToYellow(TrafficLight trafficLight) {
        System.out.println("红灯不能切换到黄灯!!!");
    }

    @Override
    public void switchToRed(TrafficLight trafficLight) {
        System.out.println("已是红灯,无需切换。。。");
    }
}

(绿灯实现类,Green,注意切换成功后修改状态)

/**
 * 绿灯
 */
public class Green implements State {

    @Override
    public void switchToGreen(TrafficLight trafficLight) {
        System.out.println("已是绿灯,无需切换。。。");
    }

    @Override
    public void switchToYellow(TrafficLight trafficLight) {
        trafficLight.setState(new Yellow());
        System.out.println("成功切换到黄灯~~~");
    }

    @Override
    public void switchToRed(TrafficLight trafficLight) {
        System.out.println("绿灯不能切换到红灯!!!");
    }
}

(黄灯实现类,Yellow,注意切换成功后修改状态)

/**
 * 黄灯
 */
public class Yellow implements State {

    @Override
    public void switchToGreen(TrafficLight trafficLight) {
        System.out.println("黄灯不能切换到绿灯!!!");
    }

    @Override
    public void switchToYellow(TrafficLight trafficLight) {
        System.out.println("已是黄灯,无需切换。。。");
    }

    @Override
    public void switchToRed(TrafficLight trafficLight) {
        trafficLight.setState(new Red());
        System.out.println("成功切换到红灯~~~");
    }
}

(信号灯类,TrafficLight,只需调用抽象方法即可)

/**
 * 交通信号灯
 */
public class TrafficLight {

    /**
     * 默认状态:红灯
     */
    State state = new Red();

    /**
     * 设置灯状态
     */
    public void setState(State state) {
        this.state = state;
    }

    /**
     * 切换到绿灯
     */
    public void switchToGreen() {
        state.switchToGreen(this);
    }

    /**
     * 切换到黄灯
     */
    public void switchToYellow() {
        state.switchToYellow(this);
    }

    /**
     * 切换到红灯
     */
    public void switchToRed() {
        state.switchToRed(this);
    }
}

(客户端,Client)

public class Client {
    public static void main(String[] args) {
        TrafficLight trafficLight = new TrafficLight();

        trafficLight.switchToGreen();
        trafficLight.switchToYellow();
        trafficLight.switchToRed();
    }
}

执行如下

在这里插入图片描述

看下来,使用状态模式,减少了单个类使用大量if-else分支处理复杂逻辑的代码,使代码便于维护,后续还有其他状态,如粉灯、蓝灯,只需要增加对应的类,对应的抽象方法即可,不需要更改原来的代码。

综合来看,状态模式,将原本的代码(code)层面上的结构化,转为了类(class)层面上的结构化,这也是其他设计模式的大体思想。

使用场景

在《设计模式就该这样学》(P349)这本书中,提到状态模式适用于以下场景:

(1)行为随状态改变而改变的场景;

(2)一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态;

总结

本文介绍了行为型设计模式中的状态模式,参考《设计模式就该这样学》、《秒懂设计模式》两书,交通信号灯场景是《秒懂设计模式》中的举例。

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

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

相关文章

换ip是换网络的意思吗?怎么换ip地址

在数字化时代,IP地址作为我们在网络世界的"身份证",其重要性不言而喻。许多人常将"换IP"与"换网络"混为一谈,实际上两者虽有联系却存在本质区别。本文将澄清这一概念误区,并详细介绍多种更换IP地址…

手机归属地查询接口如何用Java调用?

一、什么是手机归属地查询接口? 是一种便捷、高效的工具,操作简单,请求速度快。它不仅能够提高用户填写地址的效率,还能帮助企业更好地了解客户需求,制定个性化的营销策略,降低风险。随着移动互联网的发展…

随笔20250530 C# 整合 IC卡读写技术解析与实现

以下是一个完整、最简化的 FeliCa 读取整合示例(无需 SDK,基于 PCSC NuGet 包),你可以直接运行这个控制台程序,验证能否识别 RC-S300 并读取卡片 UID: 🧪 示例说明 📦 使用 NuGet 包…

基于爬取的典籍数据重新设计前端界面

1.BooksView(书籍列表页) 2.ClassicsView(目录页) 3.管理员端

揭秘 NextJS Script 组件

揭秘 NextJS Script 组件 Next.js 的 Script 组件是对原生 <script> 标签的增强封装&#xff0c;主要区别和优势如下&#xff1a; 自动优化加载策略&#xff08;支持按需/延迟加载&#xff09;避免重复加载内置性能优化&#xff08;如预加载、回调钩子&#xff09;简化…

【C++/Linux】TinyWebServer前置知识之IP协议详解

目录 IPv4地址 分类 IP数据报分片 IP 协议在传输数据报时&#xff0c;将数据报分为若干分片&#xff08;小数据报&#xff09;后进行传输&#xff0c;并在目的系统中进行重组&#xff0c;这一过程称为分片&#xff08;Fragmentation&#xff09;。 IP模块工作流程​编辑 I…

Codeforces Round 1028 (Div. 2)(A-D)

题面链接&#xff1a;Dashboard - Codeforces Round 1028 (Div. 2) - Codeforces A. Gellyfish and Tricolor Pansy 思路 要知道骑士如果没了那么这个人就失去了攻击手段&#xff0c;贪心的来说我们只需要攻击血量少的即可&#xff0c;那么取min比较一下即可 代码 void so…

记录一个梦,借助大语言模型图片生成

梦见家门口有一条大河&#xff0c;但大河和其它景物都是灰暗没有鲜艳色彩很普通的梦中场景。大河似乎是长江的支流&#xff0c;但也可能有一个响亮的名字似乎是金沙江。 突然看到一条金红色的龙在快速游动&#xff0c;不敢相信自己的眼睛&#xff0c;因为一直不相信有这种生物…

android binder(二)应用层编程实例

一、binder驱动浅析 从上图看出&#xff0c;binder的通讯主要涉及三个步骤。 在 Binder Server 端定义好服务&#xff0c;然后向 ServiceManager 注册服务在 Binder Client 中向 ServiceManager 获取到服务发起远程调用&#xff0c;调用 Binder Server 中定义好的服务 整个流…

【深度学习】17. 深度生成模型:DCGAN与Wasserstein GAN公式深度推导

深度生成模型:DCGAN与Wasserstein GAN公式深度推导 深度卷积生成对抗网络 DCGAN 在原始 GAN 框架中&#xff0c;生成器和判别器通常使用全连接层构建&#xff0c;这限制了模型处理图像的能力。为此&#xff0c;Radford 等人在 2016 年提出了 DCGAN&#xff08;Deep Convoluti…

设计模式——命令设计模式(行为型)

摘要 本文介绍了命令设计模式&#xff0c;这是一种行为型设计模式&#xff0c;用于将请求封装为对象&#xff0c;实现请求的解耦和灵活控制。它包含命令接口、具体命令、接收者、调用者和客户端等角色&#xff0c;优点是解耦请求发送者与接收者&#xff0c;支持命令的排队、记…

03 APP 自动化-定位元素工具元素定位

文章目录 一、Appium常用元素定位工具1、U IAutomator View Android SDK 自带的定位工具2、Appium Desktop Inspector3、Weditor安装&#xff1a;Weditor工具的使用 4、uiautodev通过定位工具获取app页面元素有哪些属性 二、app 元素定位方法 一、Appium常用元素定位工具 1、U…

PABD 2025:大数据与智慧城市管理的融合之道

会议简介 2025年公共管理与大数据国际会议&#xff08;ICPMBD 2025&#xff09;确实在海口举办。本次会议将围绕公共管理与大数据的深度融合、数据分析在公共管理中的应用、大数据驱动的政策制定与优化等议题展开深入研讨。参会者将有机会聆听前沿学术报告&#xff0c;分享研究…

Golang持续集成与自动化测试和部署

概述 Golang是一门性能优异的静态类型语言&#xff0c;但因其奇快的编译速度&#xff0c;结合DevOps, 使得它也非常适合快速开发和迭代。 本文讲述如何使用Golang, 进行持续集成与自动化测试和部署。主要使用了以下相关技术&#xff1a; dep&#xff1a; 进行包的依赖管理gin…

mysql离线安装教程

1.下载地址: https://downloads.mysql.com/archives/community/ 2.上传安装包到系统目录,并解压 tar -xvf mysql-8.0.34-1.el7.x86_64.rpm-bundle.tar3.检查系统中是否存在mariadb的rpm包 rpm -qa|grep mariadb存在则删除 rpm -e xxx4.解压完后执行如下命令安装 sudo rpm -iv…

基于FPGA的VGA显示文字和动态数字基础例程,进而动态显示数据,类似温湿度等

基于FPGA的VGA显示文字和数字 前言一、VGA显示参数二、字模生成三、代码分析1.vga_char顶层2.vga_ctrl驱动文件3.vga_pic数据准备文件 总结 前言 结合正点原子以及野火的基础例程&#xff0c;理解了VGA本身基本协议&#xff0c;VGA本身显示像素为640*480&#xff0c;因此注意生…

力扣刷题Day 68:搜索插入位置(35)

1.题目描述 2.思路 方法1&#xff1a;回溯的二分查找。 方法2&#xff1a;看到了一个佬很简洁的写法&#xff0c;代码贴在下面了。 3.代码&#xff08;Python3&#xff09; 方法1&#xff1a; class Solution:def searchInsert(self, nums: List[int], target: int) ->…

使用Python绘制节日祝福——以端午节和儿童节为例

端午节 端午节总算是回家了&#xff0c;感觉时间过得真快&#xff0c;马上就毕业了&#xff0c;用Python弄了一个端午节元素的界面&#xff0c;虽然有点不像&#xff0c;祝大家端午安康。端午节粽子&#xff08;python&#xff09;_python画粽子-CSDN博客https://blog.csdn.net…

C#项目07-二维数组的随机创建

实现需求 创建二维数组&#xff0c;数组的列和宽为随机&#xff0c;数组内的数也是随机 知识点 1、Random类 Public Random rd new Random(); int Num_Int rd.Next(1, 100);2、数组上下限。 //定义数组 int[] G_Array new int[1,2,3,4];//一维数组 int[,] G_Array_T …

光伏功率预测 | LSTM多变量单步光伏功率预测(Matlab完整源码和数据)

光伏功率预测 | MATLAB实现基于LSTM长短期记忆神经网络的光伏功率预测 目录 光伏功率预测 | MATLAB实现基于LSTM长短期记忆神经网络的光伏功率预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 光伏功率预测 | LSTM多变量单步光伏功率预测&#xff08;Matlab完整源码和…