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

在变幻的时光中,状态如诗篇般细腻流转。

文章目录

  • 一、可调节的灯光
  • 二、状态模式
  • 三、状态模式的核心组件
  • 四、运用状态模式
  • 五、状态模式的应用场景
  • 六、小结
  • 推荐阅读

一、可调节的灯光

场景假设:我们有一个电灯,它可以被打开和关闭。用户可以通过一个开关来改变电灯的状态。

/**
 * 表示可以开关的灯的类。
 */
public class Light {
    private String state; // 灯的当前状态,可能是"ON"或者"OFF"

    /**
     * 构造方法,初始化灯的状态为"OFF"。
     */
    public Light() {
        this.state = "OFF";
    }

    /**
     * 开关灯的状态。
     * 如果灯当前为"OFF",则将其改为"ON"并打印"灯已打开"。
     * 如果灯当前为"ON",则将其改为"OFF"并打印"灯已关闭"。
     */
    public void switchState() {
        if ("OFF".equals(state)) {
            state = "ON";
            System.out.println("灯已打开");
        } else {
            state = "OFF";
            System.out.println("灯已关闭");
        }
    }
}

上面的代码虽然能够实现需求,因为只有两种状态。但是,如果电灯有更多的状态,比如“调暗”、“调亮”、“闪烁”等,那么 switchState 方法就会变得非常复杂,充满了 if-else 语句。这将使代码难以阅读和维护。

二、状态模式

状态模式(State Pattern)是一种行为型设计模式,它允许对象在其内部状态发生改变时改变其行为,使其看起来像是改变了其类。状态模式的关键思想是将对象的行为封装在不同的状态对象中,并且在状态转换时可以动态地改变对象的行为。

三、状态模式的核心组件

状态模式的核心组件包括以下几个角色:

  1. Context(上下文):上下文是拥有状态的对象。它定义了客户端感兴趣的接口,并且维护一个当前状态对象,这个状态对象定义了当前的状态和相应的行为。Context 可以通过状态对象来改变它的行为。
  2. State(状态):状态是一个接口或者抽象类,它封装了与 Context 的一个特定状态相关的行为。在 State 接口或者抽象类中定义了所有具体状态类所共享的方法,这些方法的实现将依赖于当前状态。通常,这些方法处理与状态相关的操作,如请求或者事件。
  3. ConcreteState(具体状态):具体状态类实现了 State 接口或者继承了 State 抽象类。每个具体状态类实现了与 Context 的一个状态相关的行为。例如,在电梯系统中,可能会有开门状态、关门状态、运行状态和停止状态等具体状态类。

在这里插入图片描述

这个类图展示了状态模式的核心组成部分:

  • State 接口定义了 doAction(Context) 方法,表示所有具体状态类(OpenState 和 CloseState)需要实现的方法。
  • OpenState 和 CloseState 类分别实现了 State 接口,并实现了 doAction(Context) 方法来处理具体的状态操作。
  • Context 类包含一个状态接口类型的私有成员变量 state,通过 setState(State) 方法设置当前的状态,并通过 request() 方法执行当前状态的动作。

四、运用状态模式

场景假设:我们有一个电灯,它可以被打开和关闭。用户可以通过一个开关来改变电灯的状态。电灯有更多的状态,比如“调暗”、“调亮”、“闪烁”等。

  1. 定义状态接口:首先,我们需要定义一个状态接口,该接口声明了所有具体状态类需要实现的方法。在我们的例子中,我们可以定义一个 LightState 接口,该接口有一个 switchState 方法。

    // 定义状态接口
    public interface LightState {
        // 声明改变状态的方法,接收一个 Light 对象作为参数
        void switchState(Light light);
    }
    
  2. 创建具体状态类:然后,我们需要为每种状态创建一个具体的状态类。这些类需要实现状态接口,并实现接口中声明的方法。在我们的例子中,我们可以创建 OnState 和 OffState 类。

    // 创建具体状态类:打开状态
    public class OnState implements LightState {
        @Override
        public void switchState(Light light) {
            // 改变 Light 对象的状态为 DimState
            light.setState(new DimState());
            System.out.println("Light is dimmed");
        }
    }
    
    // 创建具体状态类:关闭状态
    public class OffState implements LightState {
        @Override
        public void switchState(Light light) {
            // 改变 Light 对象的状态为 OnState
            light.setState(new OnState());
            System.out.println("Light is turned ON");
        }
    }
    
    // 创建具体状态类:调暗状态
    public class DimState implements LightState {
        @Override
        public void switchState(Light light) {
            // 改变 Light 对象的状态为 BlinkState
            light.setState(new BlinkState());
            System.out.println("Light is blinking");
        }
    }
    
    // 创建具体状态类:闪烁状态
    public class BlinkState implements LightState {
        @Override
        public void switchState(Light light) {
            // 改变 Light 对象的状态为 OffState
            light.setState(new OffState());
            System.out.println("Light is turned OFF");
        }
    }
    
  3. 在上下文类中使用状态:最后,我们需要在上下文类中使用这些状态。上下文类维护一个对状态对象的引用,该引用可以在运行时更改。在我们的例子中,Light 类就是上下文类。

    // 创建上下文类:电灯
    public class Light {
        // Light 对象维护一个对状态对象的引用
        private LightState state;
    
        public Light() {
            // 初始状态为 OffState
            this.state = new OffState();
        }
    
        // 设置 Light 对象的状态
        public void setState(LightState state) {
            this.state = state;
        }
    
        // 切换 Light 对象的状态
        public void switchState() {
            state.switchState(this);
        }
    }
    
  4. 客户端:通过客户端测试

    public class Client {
        public static void main(String[] args) {
            // 创建一个 Light 对象
            Light light = new Light();
    
            // 切换 Light 对象的状态
            light.switchState(); // 打开电灯
            light.switchState(); // 调暗电灯
            light.switchState(); // 电灯开始闪烁
            light.switchState(); // 关闭电灯
        }
    }
    

五、状态模式的应用场景

状态模式在许多场景中都非常有用,特别是当一个对象的行为取决于其状态,并且它必须在运行时根据状态改变其行为时。以下是一些常见的应用场景:

  1. 用户界面(UI):在许多用户界面中,元素的行为会根据其状态(如禁用、选中、悬停等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。
  2. 游戏开发:在游戏开发中,角色的行为通常会根据其状态(如站立、跑动、跳跃、攻击等)而改变。使用状态模式,我们可以为每种状态创建一个状态类,使得代码更易于理解和维护。
  3. 工作流引擎:在工作流引擎中,任务的行为会根据其状态(如新建、进行中、已完成等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。
  4. 网络连接:网络连接的行为会根据其状态(如打开、关闭、等待等)而改变。状态模式可以帮助我们管理这些状态,并使状态转换的逻辑更加清晰。

六、小结

状态模式是一种优秀的设计模式,适用于那些对象行为会随着内部状态变化而变化的情况。它通过将对象的状态和行为分离,使得系统更加灵活、易于理解和扩展。

推荐阅读

  1. 深入探究 Spring Boot Starter:从概念到实践
  2. 深入理解 Java 中的 volatile 关键字
  3. OAuth 2.0:现代应用程序的授权标准
  4. Spring 三级缓存
  5. 深入了解 MyBatis 插件:定制化你的持久层框架

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nvidia jetson Orin/Nano + 智能座舱摄像头实现车载AI视觉

智能座舱系统包括DMS(Driver Monitor System)驾驶员疲劳监测系统和OMS乘员监测系统,通过在车内安装摄像头感知驾驶员和乘客的行为以及车内状况:DMS摄像头能够实现驾驶员疲劳监测、驾驶员注意力监测、危险驾驶行为监测以及驾驶员身…

【python】python基于tkinter的学生成绩管理系统(源码+数据文件)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

如何做到高级Kotlin强化实战?(一)

高级Kotlin强化实战(一) 第一章 Kotlin 入门教程1.Kotlin 入门介绍2.Kotlin 与 Java 比较 第一章 Kotlin 入门教程 1.Kotlin 入门介绍 Kotlin 概述 Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言。它主要是 JetBrains 开发团队所开发出来的编程…

打靶记录——靶机medium_socnet

靶机下载地址 https://www.vulnhub.com/entry/boredhackerblog-social-network,454/ 打靶过程 由于靶机和我的Kali都处于同一个网段,所以使用arpscan二次发现技术来识别目标主机的IP地址 arpscan -l除了192.168.174.133,其他IP都是我VMware虚拟机正…

算法力扣刷题 二十六【459.重复的子字符串】

前言 字符串篇,继续。 记录 二十六【459.重复的子字符串】 一、题目阅读 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 示例 1: 输入: s "abab" 输出: true 解释: 可由子串 "ab" 重复两次构成。示例…

在TkinterGUI界面显示WIFI网络(ESP32s3)摄像头画面

本实验结合了之前写过的两篇文章Python调用摄像头,实时显示视频在Tkinter界面以及ESP32 S3搭载OV2640摄像头释放热点(AP)工作模式–Arduino程序,当然如果手头有其他可以获得网络摄像头的URL即用于访问摄像头视频流的网络地址&…

浅谈Tomcat

文章目录 一、什么是Tomcat?二、Tomcat的下载安装三、使用tomcat访问资源 一、什么是Tomcat? Tomcat 就是一个 HTTP 服务器。 前面我们聊了HTTP服务器,像我们在网页输入URL,其实就是在给人家的HTTP服务器发送请求,既…

计算机网络之数据通信原理(中)

上节内容传送口:数据通信原理基础 1.数据传输方式 1.1并行传输 并行传输: 字符编码的各个比特同时传输 特点: 一个比特时间内可传输一个字符,传输速度快,每个比特传输要求一个单独的信道支持,通信成本高&#xf…

红黑树插入删除流程(流程图)

红黑树插入删除流程(流程图) 红黑树性质 左根右(二叉树)根叶黑(根节点是黑色的)不红红(不存在相邻两个红色节点)黑路同(对于每个节点,从该节点出发到任一空叶节点所经过…

收银系统源码-千呼新零售【全场景收银】

千呼新零售2.0系统是零售行业连锁店一体化收银系统,包括线下收银线上商城连锁店管理ERP管理商品管理供应商管理会员营销等功能为一体,线上线下数据全部打通。 适用于商超、便利店、水果、生鲜、母婴、服装、零食、百货、宠物等连锁店使用。 详细介绍请…

intellij idea中使用R语言plot画图无图像问题

1、在intellij idea中使用R语言plot函数时,会遇到各种各样的问题,会出现图片不显示问题, 可以看到,目前我电脑r语言版本为4.2.1,输入下面代码: # # 安装包 # install.packages(ggplot2) # library(ggplot2…

理解MySQL核心技术:外键的概念作用和应用实例

引言 在数据库管理系统(DBMS)中,外键(Foreign Key)是维持数据一致性和实现数据完整性的重要工具。本文将详细介绍MySQL外键的基本概念、作用,以及相关的操作指南和应用实例,帮助读者掌握并灵活…

实现了Map接口的HashMap

HashMap 底层主要由以下几个部分组成&#xff1a; 数组 (Node<K,V>[] table): 这是一个数组&#xff0c;存储的是链表的头节点。默认大小为 16。链表 (Linked List): 当发生哈希冲突时&#xff0c;即不同的键具有相同的哈希值&#xff0c;HashMap 使用链表来解决冲突。链…

2024年06月CCF-GESP编程能力等级认证Scratch图形化编程一级真题解析

本文收录于《Scratch等级认证CCF-GESP图形化真题解析》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 一、单选题(每题 3 分,共 30 分) 第1题 小杨父母带他到某培训机构给他报名参加 CCF 组织的 GESP 认证考试的第 1级,那他可以选择的认证语言有几种?( ) A、…

C++ | Leetcode C++题解之第204题计数质数

题目&#xff1a; 题解&#xff1a; class Solution { public:int countPrimes(int n) {vector<int> primes;vector<int> isPrime(n, 1);for (int i 2; i < n; i) {if (isPrime[i]) {primes.push_back(i);}for (int j 0; j < primes.size() && i …

百度网盘下载速度慢的解决办法

目录 一、背景 二、解决办法 1、点击三个竖点&#xff0c;再点设置 2、点击传输&#xff0c;再点击去开启该功能 3、点击同意&#xff0c;开启优化速率 三、结果 四、备注 一、背景 当你不是百度网盘会员时&#xff0c;你在使用百度网盘下载时&#xff0c;是否下载速度太…

isalnum()方法——判断字符串是否由字母和数字组成

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法参考 isalnum()方法用于判断字符串是否由字母和数字组成。isalnum()方法的语法格式如下&#xff1a; str.isalnum() 如果字符串中至少有一个字…

缺少msvcp140一键修复方法,快速解决msvcp140.dll丢失问题

日常中电脑已经成为我们生活和工作中不可或缺的工具。然而&#xff0c;在使用电脑的过程中&#xff0c;我们常常会遇到一些问题&#xff0c;其中之一就是电脑运行软件时提示找不到msvcp140.dll。这个问题会导致软件无法启动运行&#xff0c;但只要我们了解其原因并采取相应的解…

六月,允许自己做自己,别人做别人

今天结束后&#xff0c;2024 就过去一半了。 年初的规划完成一半了吗&#xff1f;如果没有也没关系&#xff0c;做你自己继续前进。 家人来北京旅游&#xff0c;我累趴了 六月初&#xff0c;我搬家了&#xff0c;这次租了一整套房&#xff0c;是一个小俩居、还带一个小阁楼。…

鸿蒙如何打包应用程序

总结鸿蒙应用程序包 之前文章详细讲解了关于三种程序包的内容&#xff0c;现在简单总结一下&#xff1a; 1. 总结 首先需要搞清楚鸿蒙项目的模块Module的分类: Module分为“Ability”和“Library”两种类型 HAP HAP: Harmony Ability Package , 叫做鸿蒙Ability包。 “Abil…