22、设计模式之状态模式(State)

一、什么是状态模式
状态模式是一种行为型设计模式。它允许对象在内部状态发生改变时改变它的行为,简单地讲就是,一个拥有状态的context对象,在不同状态下,其行为会发生改变。

二、角色组成

上下文(Context):定义客户端需要的接口,并且负责具体状态的切换。
抽象状态(Abstract State):抽象状态类是所有具体状态类的基类或接口。负责定义该状态下的行为,可以一个或多个。
具体状态(Concrete State):具体状态类实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。

三、 优缺点
优点:

客户端只需要与上下文对象进行交互,而不需要了解具体状态对象的切换和行为实现细节。
状态模式遵循开闭原则,使系统更加可扩展。当需要增加新的状态时,只需添加新的具体状态类,而无需修改上下文对象或其他状态类。
避免了使用大量的条件语句来控制对象在不同状态下的行为。它将状态相关的代码分散到各个具体状态类中,使代码更加清晰、可读性更高,易于维护和扩展。
状态转换被封装在具体状态类中,可根据需求定义不同的状态切换规则,使得状态转换过程可控、灵活。
缺点:

状态模式增加了系统中类的数量,引入了更多的类,可能会增加代码的复杂性。
对于简单、直接的状态机,使用状态模式可能会显得过于繁琐,增加了代码的冗余。在这种情况下,可以采用简化的条件语句来处理状态转换。
四、应用场景
4.1 生活场景
自动售货机:自动售货机中的商品状态会随着库存量的变化而改变。当库存为0时,商品状态为"售罄";当库存充足时,商品状态为"可购买";
购物车状态:在线购物网站中,购物车可以有不同的状态,比如空、有商品、结算中等。每个状态下,购物车的显示内容和可用操作不同。

4.2 java场景

Thread类:线程有new、Runnable、Blocked、Waiting、Time_Waiting和Terminated状态。这些状态代表了线程在不同的执行阶段或操作中的不同状态。Thread类内部使用了状态模式来管理和切换线程的状态。
Connection接口:Connection接口表示与数据库的连接,它可能处于不同的状态,比如打开、关闭、空闲、繁忙等。Connection接口在不同的状态下提供了不同的操作方法,以便与数据库进行交互。

五、代码实现
下面以自动售卖机为例,解释一下状态模式。我们可以将售卖机分为三个部分:自动售卖机(Machine)类作为上下文(Context),状态(State)作为状态的抽象状态(Abstract State),售卖机的三个状态——未投币(NoCoinState)、已投币(HasCoinState)、出售中(SlodState)作为具体状态(Concrete State)

5.0 UML类图
在这里插入图片描述
5.1 State——抽象状态

/**
 *
 * 1.抽象状态(Abstract State):状态接口
 * 定义:定义该状态下的行为,可以一个或多个。
 */
public interface State {
    //投币
    void insertCoin();
    //选择商品
    void selectProduct();
    //发放商品
    void dispense();
}

5.2 具体状态

/**
 * 
 * 2.具体状态(Concrete State):未投币状态
 * 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。
 */
public class NoCoinState implements State{
    private Machine machine;
 
    public NoCoinState(Machine machine) {
        this.machine = machine;
    }
 
    @Override
    public void insertCoin() {
        System.out.println("已投币");
        // 切换到已投币状态
        machine.setState(machine.getHasCoinState());
    }
 
    @Override
    public void selectProduct() {
        System.out.println("请先投币");
    }
 
    @Override
    public void dispense() {
        System.out.println("请先投币选择商品");
    }
}
/**
 * 
 * 2.具体状态(Concrete State):已投币状态
 * 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。
 */
public class HasCoinState implements State{
 
    private Machine machine;
 
    public HasCoinState(Machine machine) {
        this.machine = machine;
    }
 
    @Override
    public void insertCoin() {
        System.out.println("已投币,请勿重复投币");
    }
 
    @Override
    public void selectProduct() {
        System.out.println("商品已选择");
        // 切换到出售状态
        machine.setState(machine.getSoldState());
    }
 
    @Override
    public void dispense() {
        System.out.println("请先选择商品");
    }
}
/**
 *
 * 2.具体状态(Concrete State):出售状态
 * 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。
 */
public class SoldState implements State{
    private Machine machine;
 
    public SoldState(Machine machine) {
        this.machine = machine;
    }
 
    @Override
    public void insertCoin() {
        System.out.println("正在出售商品,请稍等");
    }
 
    @Override
    public void selectProduct() {
        System.out.println("正在出售商品,请稍等");
    }
 
    @Override
    public void dispense() {
        System.out.println("商品已发放");
        //切换到未投币状态
        machine.setState(machine.getNoCoinState());
    }
}

5.3 Machine——上下文

/** 
 * 3.上下文(Context):自动售卖机
 * 定义:定义客户端需要的接口,并且负责具体状态的切换。
 */
public class Machine {
    //未投币状态
    private State noCoinState;
    //已投币状态
    private State hasCoinState;
    //出售状态
    private State soldState;
    //当前状态
    private State currentState;
 
    public Machine() {
        noCoinState = new NoCoinState(this);
        hasCoinState = new HasCoinState(this);
        soldState = new SoldState(this);
        currentState = noCoinState; // 初始状态为未投币状态
    }
 
    public void setState(State state) {
        currentState = state;
    }
 
    public State getNoCoinState() {
        return noCoinState;
    }
 
    public State getHasCoinState() {
        return hasCoinState;
    }
 
    public State getSoldState() {
        return soldState;
    }
 
    public void insertCoin() {
        currentState.insertCoin();
    }
 
    public void selectProduct() {
        currentState.selectProduct();
    }
 
    public void dispense() {
        currentState.dispense();
    }
}

5.4 testState

/**
 *
 * 状态模式测试类
 */
@SpringBootTest
public class TestState {
 
    @Test
    void testState(){
        //创建上下文对象(自动售卖机)
        Machine machine = new Machine();
 
        System.out.println("=======直接选择商品=======");
        machine.selectProduct();
 
        System.out.println("======投币--->选择商品--->发放商品=======");
        machine.insertCoin();
        machine.selectProduct();
        machine.dispense();
 
        System.out.println("=======投币--->发放商品=======");
        machine.insertCoin();
        machine.dispense();
    }
}

在这里插入图片描述
六、总结
熟悉策略模式的小伙伴可能会发现,状态模式和策略模式的UML类图几乎一摸一样,但这两中模式的应用场景是不一样的。策略模式的多种算法行为选择一种就能满足,彼此之间是独立的;而状态模式中各个状态间存在相互关系,彼此之间在一定条件下存在自动切换状态的效果,并且用户不能指定状态,只能设置初始状态。

以下情况出现,可以考虑状态模式:

当一个对象的行为取决于其内部状态,并且在不同状态下具有不同的行为时
当对象的行为在运行时需要根据其状态动态改变,并且需要避免大量的条件语句和分支判断时。
当代码中存在大量的条件语句和分支逻辑,并且这些逻辑与对象的状态变化相关时。
当对象的状态之间存在复杂的转换关系,并且需要维护状态转换的一致性时。

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

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

相关文章

阿里云函数计算服务推出的AgentCraft智能体应用开发平台助力你轻松搭建企业的微信知识库-安装部署介绍

需要开通的资源:函数计算服务、PostgreSQL、NAS AgentCraft 是一个面向开发者与企业用户的开源智能体应用开发平台,它致力于加速并简化智能体应用的构建过程。您能够便捷地将AgentCraft部署至阿里云的公共或专属环境,并确保从基本模型、应用…

【Ubuntu 20.04】ROS——话题、服务与动作编程

【Ubuntu 20.04】ROS——话题、服务与动作编程 工作空间1.创建工作空间2.编译工作空间3.设置环境变量4.检查环境变量 功能包1.创建功能包2.编译功能包 一、话题(一)创建发布者(二)创建订阅者(三)编译代码&a…

android MMKV数据持久化缓存集合

前言 最近在使用mmkv缓存的时候 发现没有集合缓存 非常不方便 自己写一个方法 MMKV public class MmkvUtils {private MmkvUtils() {throw new UnsupportedOperationException("u cant instantiate me...");}public static void init() {MMKV.initialize(LeoUtils…

详解Postman使用

简介: 1.简介 PostMan,一款接口调试工具。 特点: 可以保留接口请求的历史记录 可以使用测试集Collections有效管理组织接口 可以在团队之间同步接口数据 1.简介 PostMan,一款接口调试工具。 特点: 可以保留接口请求…

分享一下 iOS 发布/测试证书 申请过程

1.使用 已开通iOS开发者 的账号登陆 Apple Developer Apple Developer 2.点击下图右上角的 Account(账户) 点击下图中的 certificates(证书) 然后会挑战至下图所示页面 3.然后先要注册一个 App id 点击 register 就完成了 4.…

如何从无法开机的手机中恢复数据?4个解决方案解决了

Android 手机保存着大量有价值的数据,包括珍贵的照片、重要文档,对于许多人来说还包括整个音乐库。但是,您的 Android 手机可能会因电池电量耗尽、软件问题、硬件故障或意外损坏而拒绝开机或屏幕损坏。 无论原因如何,我们都将指导…

回收小程序系统后台管理功能

会员管理:管理员可以查看和管理会员的基本信息,如姓名、联系方式、寄送地址和订单记录等。 产品管理:对回收物品进行管理,包括分类、规格设定、数据统计等。 订单管理:对所有订单进行追踪和管理,确保订单处…

GPT实战系列-LangChain构建自定义Agent

GPT实战系列-LangChain构建自定义Agent LangChain GPT实战系列-LangChain如何构建基通义千问的多工具链 GPT实战系列-构建多参数的自定义LangChain工具 GPT实战系列-通过Basetool构建自定义LangChain工具方法 GPT实战系列-一种构建LangChain自定义Tool工具的简单方法 GPT…

Vue组件中引入jQuery

两种在vue中引入jQuery的方式 1、普通html中使用jQuery 将jQuer的文件导入到项目中&#xff0c;然后直接使用<script src"jQuery.js"></script>即可。 <script src"jQuery.js"></script> 2、vue组件中使用jQuery 安装依赖 c…

【ARM】MDK在programming algorithm界面添加FLM

【更多软件使用问题请点击亿道电子官方网站查询】 1、 文档目标 解决在programming algorithm界面中无法添加想要的Flash编程算法的问题 2、 问题场景 在对于Debug进行Flash Download进行配置的时候&#xff0c;在programming algorithm界面中有对应的Flash编程算法。可以通过…

SQLite—免费开源数据库系列文章目录

SQLite系列相关文章较多特开本文为了便于读者阅读特写了本索引和目录之用本文将不断更新中有需要的读者可以收藏本文便于导航到各个专题( 持续更新中......)。收藏一篇等于收藏一个系列文章 简介类&#xff1a; SQLite——世界上部署最广泛的免费开源数据库&#xff08;简介&…

openssl3.2 - exp - export ecc pubkey from ecc priv key

文章目录 openssl3.2 - exp - export ecc pubkey from ecc priv key概述笔记END openssl3.2 - exp - export ecc pubkey from ecc priv key 概述 前面实验已经生成了ECC私钥, 现在做从ECC私钥(内容为公私钥对, 里面既有私钥信息, 也有公钥信息)导出ECC公钥. 实验对应的命令行…

单链表——增删查改

本节复习链表的增删查改 首先&#xff0c; 链表不是连续的&#xff0c; 而是通过指针联系起来的。 如图&#xff1a; 这四个节点不是连续的内存空间&#xff0c; 但是彼此之间使用了一个指针来连接。 这就是链表。 现在我们来实现链表的增删查改。 目录 单链表的全部接口…

Windows达梦数据库(下载及使用)

解压安装包 点击最后一个文件 下一步 接受 下一步 下一步 下一步 点击初始化 开始

k8s-Istio服务网络 27

官网&#xff1a;https://istio.io/latest/zh/about/service-mesh/ Istio与k8s的区别 SpringCloud传统微服务结合k8s与Istio与k8s结合&#xff1a; Istio数据面&#xff1a;通过envoy以sidecar方式拦截svc的流量来进行治理。 Istio控制面&#xff1a;pilot list/watch APIserv…

数字孪生与智慧城市:实现城市治理现代化的新路径

随着信息技术的迅猛发展&#xff0c;智慧城市已成为城市发展的必然趋势。数字孪生技术作为智慧城市建设的重要支撑&#xff0c;以其独特的优势为城市治理现代化提供了新的路径。本文将探讨数字孪生技术在智慧城市中的应用&#xff0c;以及如何实现城市治理的现代化。 一、数字…

HADOOP完全分布式搭建(饭制版)

HADOOP完全分布式搭建&#xff08;饭制版&#xff09; 1.虚拟机安装 安装系统 点击VMware Workstation左上角文件&#xff0c;新建虚拟机 选择自定义&#xff0c;点击下一步 点击下一步 选择稍后安装操作系统&#xff08;后续我们使用的操作系统为CentOS7&#xff09;,点击…

【研发日记】,Matlab/Simulink开箱报告(十)——Requirements Toolbox

前言 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;五&#xff09;——S-Fuction模块(C MEX S-Function)》 见《开箱报告&#xff0c;Simulink Toolbox库模块使用指南&#xff08;六&#xff09;——S-Fuction模块&#xff08;TLC&#xff09;》 见《开…

2.案例、鼠标时间类型、事件对象参数

案例 注册事件 <!-- //disabled默认情况用户不能点击 --><input type"button" value"我已阅读用户协议(5)" disabled><script>// 分析&#xff1a;// 1.修改标签中的文字内容// 2.定时器// 3.修改标签的disabled属性// 4.清除定时器// …

构建部署_Jenkins介绍与安装

构建部署_Jenkins介绍与安装 构建部署_Jenkins介绍与安装Jenkins介绍Jenkins安装 构建部署_Jenkins介绍与安装 Jenkins介绍 Jenkins是一个可扩展的持续集成引擎。 持续集成&#xff0c;就是通常所说的CI&#xff08;Continues Integration&#xff09;&#xff0c;可以说是现…