状态模式:灵活应对对象行为变化,实现状态驱动的智能设计

文章目录

  • **一、技术背景与应用场景**
    • **为何使用状态模式?**
    • **典型应用场景包括但不限于:**
  • **二、状态模式定义与结构**
  • **三、使用步骤举例**
  • **四、优缺点分析**
  • **总结**

一、技术背景与应用场景

状态模式是一种行为设计模式,用于处理一个对象在其内部状态改变时,其行为也随之发生相应变化的情况。例如,在ATM机中,用户操作(取款、存款、查询等)会引发系统状态的变化和对应的操作;游戏角色根据所处状态(行走、奔跑、战斗)执行不同的动作。

为何使用状态模式?

  1. 减少条件分支:通过将状态与相关行为封装为独立类,可显著降低业务逻辑中的嵌套或分支条件判断,提高代码可读性和维护性。
  2. 易于扩展新状态:当需要新增状态或修改状态行为时,只需创建新的状态类或调整现有状态类即可,不影响原有系统的整体结构。
  3. 职责明确:遵循单一职责原则,状态管理与状态相关的操作分离,使得各部分职责更加清晰。

典型应用场景包括但不限于:

  • 游戏开发:游戏角色的不同状态及其关联行为。
  • 设备控制:家电设备的各种工作模式切换及其响应操作。
  • 订单系统:订单流程中的不同状态(待支付、已支付、已发货、已完成等)及相应的操作处理。

二、状态模式定义与结构

状态模式包含四个核心组成部分:

在这里插入图片描述

  1. 环境角色(Context):持有当前状态,并将与状态相关的请求委托给当前状态对象来处理。
  2. 抽象状态角色(State):定义所有具体状态类需要实现的接口,通常包含一个或多个方法,用于处理来自环境角色的方法调用。
  3. 具体状态角色(Concrete State):实现了抽象状态角色声明的接口,每个具体状态对应一种特定的行为。
  4. 状态转移:在某个具体状态对象执行对应处理行为时,它可能会改变环境角色的状态引用,指向另一个具体状态对象。

三、使用步骤举例

模拟了一个简单的电商订单系统,这个系统通过状态模式来处理订单从创建到完成或取消的整个生命周期中的不同状态和操作。

  1. 抽象状态角色(OrderState):定义了所有具体状态类需要实现的方法接口,包括place()pay()ship()cancel()等。

    // 抽象状态角色
    public abstract class OrderState {
        protected Order order;
    
        public void setOrder(Order order) {
            this.order = order;
        }
    
        // 抽象方法,由具体状态类实现
        public abstract void place();   //下单
        public abstract void pay();     //支付
        public abstract void ship();    //发货
        public abstract void cancel();    //取消订单
    }
    
  2. 具体状态角色

    • CreatedState:代表订单刚创建的状态,在此状态下可以进行下单和取消操作,当调用place()时只是打印提示信息,而调用cancel()会将订单状态转换为CancelledState

      // 具体状态角色
      public class CreatedState extends OrderState {
          @Override
          public void place() {
              System.out.println("订单已创建,等待支付");
          }
      
          @Override
          public void pay() {
              System.out.println("订单已支付~");
              // 转换状态至“已支付”状态
              order.setState(new PaidState());
          }
      
          @Override
          public void ship() {
              System.out.println("请先完成支付才能发货");
          }
      
          @Override
          public void cancel() {
              System.out.println("订单已取消");
              // 设置订单为已取消状态
              order.setState(new CancelledState());
          }
      }
      
    • PaidState:代表订单已支付的状态,在此状态下无法再次下单或支付,但可以进行发货和取消操作。发货时会将订单状态转换为ShippedState,取消则转换为CancelledState

      public class PaidState extends OrderState {
          @Override
          public void place() {
              System.out.println("请勿重复下单");
          }
      
          @Override
          public void pay() {
              System.out.println("订单已支付,无需再次支付");
          }
      
          @Override
          public void ship() {
              System.out.println("订单开始发货...");
              // 转换状态至“已发货”状态
              order.setState(new ShippedState());
          }
      
          @Override
          public void cancel() {
              System.out.println("正在申请退款...");
              // 设置订单为已取消状态
              order.setState(new CancelledState());
          }
      }
      
    • ShippedState:代表订单已发货的状态,在此状态下仅能查看状态,不能执行其他操作。

      public class ShippedState extends OrderState {
          @Override
          public void place() {
              System.out.println("请勿重复下单");
          }
      
          @Override
          public void pay() {
              System.out.println("订单已支付,无需再次支付");
          }
      
          @Override
          public void ship() {
              System.out.println("订单已发货,无需再次发货");
          }
      
          @Override
          public void cancel() {
              System.out.println("您已无法取消已发货的订单");
          }
      }
      
    • CancelledState:代表订单已取消的状态,同样只能查看状态,不能执行其他操作。

      public class CancelledState extends OrderState {
          @Override
          public void place() {
              System.out.println("您的订单已取消,请重新下单");
          }
      
          @Override
          public void pay() {
              System.out.println("该订单已取消,无法进行支付");
          }
      
          @Override
          public void ship() {
              System.out.println("该订单已取消,无法发货");
          }
      
          @Override
          public void cancel() {
              System.out.println("订单已处于取消状态");
          }
      }
      
  3. 环境角色(Order):持有当前订单状态,并提供与订单状态相关联的操作方法(如place()pay()等)。当调用这些方法时,实际上是委托给当前持有的状态对象去执行相应的行为。

    // 环境角色
    public class Order {
       private OrderState state;
    
       public void setState(OrderState state) {
           this.state = state;
           state.setOrder(this);
       }
    
       public void place() {
           state.place();
       }
    
       public void pay() {
           state.pay();
       }
    
       public void ship() {
           state.ship();
       }
    
       public void cancel() {
           state.cancel();
       }
    }
    
  4. 应用端示例(OrderStateMachineDemo)
    创建一个新订单实例,初始状态下是CreatedState。然后按照实际业务流程调用place()pay()ship()cancel()方法,根据不同的状态,订单的行为会有不同的响应,并可能触发状态的转换。

// 应用端示例
public class OrderStateMachineDemo {
    public static void main(String[] args) {
        Order order = new Order();
        order.setState(new CreatedState()); // 初始状态为“已创建”

        order.place();  // 根据状态进行操作
        order.pay();
        order.ship();
        order.cancel();
    }
}

测试结果

在这里插入图片描述


四、优缺点分析

状态模式的优点在于:

  • 模块化状态行为:各状态行为被划分到各自的具体状态类中,便于理解和维护。
  • 增强灵活性:添加新状态或修改状态行为不涉及其他状态逻辑,利于扩展。
  • 消除条件分支:移除了大量基于状态判断的条件语句,提高了程序内聚性。

潜在挑战可能包括:

  • 过多具体状态类:随着状态数量增加,具体状态类的数量也会增长,可能影响系统组织结构简洁性。
  • 复杂状态转换逻辑:状态间转换规则复杂时,需额外关注状态转换的一致性和正确性。

总结

状态模式利用状态驱动的方式对对象行为进行有效管理,使得软件能够根据对象状态的变化动态调整行为。合理运用状态模式,可以提升系统对于复杂状态变化场景的适应能力,同时优化代码结构,保持高可维护性和扩展性。

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

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

相关文章

分享一个UE的SmoothStep小技巧

SmoothStep节点可以制作更平滑的动画,而如果将max参数作为值传入将value和min参数作为约束,则可以做出类似冲击波的渐变效果: 并且通过修改value与min之间的数值差,可以调节渐变。 这个技巧主要就是可以产生硬边。 比如我们可…

2024年阿里云服务器新购、续费、升级优惠政策和优惠活动大全

2024年阿里云服务器购买、续费、升级优惠政策整理,阿里云服务器优惠价格表:轻量2核2G3M服务器61元一年、2核4G4M带宽165元1年,云服务器4核16G10M带宽26元1个月、149元半年,阿里云ECS云服务器2核2G3M新老用户均可99元一年续费不涨价…

信息系统项目管理师(高项)—学习笔记

第一章信息化发展 1.1 信息与信息化 1.1.1 信息 信息是物质、能量及其属性的标示的集合,是确定性的增加。 它以物质介质为载体,在传递和反映世界各种事物存在方式、运动状态等的表征。 信息不是物质,也不是能力,它以一种普遍…

实验室预约|实验室预约小程序|基于微信小程序的实验室预约管理系统设计与实现(源码+数据库+文档)

实验室预约小程序目录 目录 基于微信小程序的实验室预约管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、微信小程序前台 2、管理员后台 (1)管理员登录 (2)实验室管理 (3)公告信息…

天府锋巢直播基地:打造西部地区成都直播基地生态圈的领军标杆

数字经济蓬勃发展,直播产业成为赋能引擎以及新的经济增长点。直播电商作为数字经济的一大板块,对我国推动数字化建设有着非常大的作用。德商产投与无锋科技联袂打造了天府锋巢直播产业基地,该成都直播基地致力于打造全域直播基地,…

某胜物流软件三个接口sql注入漏洞(附漏洞检测脚本)

免责声明 文章中涉及的漏洞均已修复,敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直接或者间接的…

Leetcoder Day20| 二叉树 part09+总结

语言:Java/Go 669. 修剪二叉搜索树 给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移…

jenkins报错:Pseudo-terminal will not be allocated because stdin is not a terminal

jenkins的流水线部分代码如下 sh ssh root192.168.2.234 << remotessh cd /var/lib/jenkins/workspace/txkc /usr/local/maven/apache-maven-3.8.6/bin/mvn clean package -U ls remotessh执行流水线出现报错&#xff1a;Pseudo-terminal will not be allocated because…

docker 启动镜像命令

Docker 的启动命令用于启动 Docker 容器。这些命令可以从基本的 docker run 命令扩展到包括多个选项和参数&#xff0c;以满足不同的需求。以下是一些常用的 Docker 启动命令和选项的示例&#xff1a; 启动一个新容器&#xff1a; docker run [OPTIONS] IMAGE [COMMAND] [ARG..…

Ubuntu系统本地部署Inis博客结合内网穿透实现远程访问本地站点

文章目录 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总…

【TCP/IP】内核网络堆栈

在Linux内核中&#xff0c;网络堆栈&#xff08;network stack&#xff09;是一套实现网络通信功能的软件包&#xff0c;负责处理数据包的发送和接收。网络堆栈按照OSI模型&#xff08;开放式系统互联通信参考模型&#xff09;或TCP/IP模型的层次结构来组织&#xff0c;实现了从…

elementPlus的table设置序号

//正常显示 不做任何操作的序列号 <el-table-column label"序号" type"index" width"50"></el-table-column>如果表格每页显示10条数据&#xff0c;这样表格的每一页的序号都是1到10。 现在有个需求是第一页显示1-10&#xff0c;第…

Python算法100例-2.4 个人所得税

完整源代码项目地址&#xff0c;关注博主私信源代码后可获取 1.问题描述2.问题分析3.算法设计4.确定程序框架5.完整的程序 1&#xff0e;问题描述 编写一个计算个人所得税的程序&#xff0c;要求输入收入金额后&#xff0c;能够输出应缴的个人所得税。个人所得税征收办法如下…

jetson nano——安装archiconda

目录 1.archiconda3我在这提供了下载链接&#xff0c;点解下面链接即可1.看好文件所在位置&#xff0c;如果装错了&#xff0c;那么环境变量的路径自己进行相应的修改。2.添加环境变量 2.可能部分伙伴输入一些激活&#xff0c;啥的命令激活不了&#xff0c;那么输入下面这些代码…

初始Nginx(基本概念)

目录 一、Nginx的概念 二、Nginx常用功能 1、HTTP(正向)代理&#xff0c;反向代理 1.1正向代理 1.2 反向代理 2、负载均衡 2.1 轮询法&#xff08;默认方法&#xff09; 2.2 weight权重模式&#xff08;加权轮询&#xff09; 2.3 ip_hash 3、web缓存 三、基础特性 四…

【Java前端技术栈】Promise

一、Promise 基本介绍 1. 传统的 Ajax 异步调用在需要多个操作的时候&#xff0c;会导致多个回调函数嵌套&#xff0c;导致代码不够直观&#xff0c;就是常说的Callback Hell 2. 为了解决上述的问题&#xff0c;Promise对象应运而生&#xff0c;在 EMCAScript 2015当中已经成…

云HIS系统源码,基于云计算技术的B/S架构的云HIS系统,二甲医院信息管理系统

云HIS系统源码&#xff0c;采用云端SaaS服务的方式提供 基于云计算技术的B/S架构的云HIS系统&#xff0c;采用云端SaaS服务的方式提供&#xff0c;使用用户通过浏览器即能访问&#xff0c;无需关注系统的部署、维护、升级等问题&#xff0c;系统充分考虑了模板化、配置化、智能…

lxml库和Xpath提取网页数据的基础与实战:完整指南与实战【第92篇—提取网页】

使用lxml库和Xpath提取网页数据的基础与实战 在网络爬虫和数据抓取中&#xff0c;从网页中提取所需信息是一项常见的任务。lxml库和Xpath是Python中用于解析和提取HTML/XML数据的强大工具。本文将介绍lxml库的基础知识&#xff0c;以及如何使用Xpath表达式来准确地提取网页数据…

CUDA自学笔记001 CUDA编程模型、CUDA线程模型及其管理、CUDA内存模型及其管理

CUDA编程模型 我们使用CUDA_C语言进行CUDA编程&#xff0c; 1&#xff0c;CUDA编程模型提供了线程抽象接口用于控制GPU中的线程 2&#xff0c;CUDA编程模型提供了内存访问控制&#xff0c;我们可以实现主机和GPU设备内存的控制&#xff0c;我们可以实现CPU和GPU之间内存的数据传…

Fibonacci 数列与黄金分割【第十届】【省赛】【研究生组】

题目描述 Fibonacci 数列是非常著名的数列&#xff1a; F [ 1 ] 1 , F [ 2 ] 1 F[1]1,F[2]1 F[1]1,F[2]1&#xff0c;对于 i > 3 &#xff0c; F [ i ] F [ i − 1 ] F [ i − 2 ] 。 i>3&#xff0c;F[i]F[i−1]F[i−2]。 i>3&#xff0c;F[i]F[i−1]F[i−2]。…