设计模式-状态模式(State)

设计模式-状态模式(State)

    • 一、状态模式概述
      • 1.1 什么是状态模式
      • 1.2 简单实现状态模式
      • 1.3 使用状态模式的注意事项
    • 二、状态模式的用途
    • 三、状态模式实现方式
      • 3.1 使用枚举类型实现状态模式
      • 3.2 使用内部类实现状态模式
      • 3.3 使用接口实现状态模式
      • 3.4 使用抽象类实现状态模式

一、状态模式概述

1.1 什么是状态模式

Java中的状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变其行为。这种模式主要用于实现对象之间的解耦,使得对象可以在不修改其结构的情况下改变其行为。

Java中的状态模式通常包括以下角色:

上下文(Context):负责维护当前状态和根据当前状态调用相应的状态处理方法。
状态(State):表示对象的状态,每个状态都有一个对应的处理方法。
具体状态(Concrete State):是状态的具体实现,继承自状态接口。

1.2 简单实现状态模式

// 状态接口
interface State {void handle(Context context);
}// 具体状态A
class ConcreteStateA implements State {@Overridepublic void handle(Context context) {System.out.println("当前状态为A");context.setState(this);}
}// 具体状态B
class ConcreteStateB implements State {@Overridepublic void handle(Context context) {System.out.println("当前状态为B");context.setState(this);}
}// 上下文类
class Context {private State state;public Context() {this.state = new ConcreteStateA(); // 初始状态为A}public void request() {state.handle(this); // 根据当前状态执行相应操作}public void setState(State state) {this.state = state; // 切换状态}
}public class Main {public static void main(String[] args) {Context context = new Context(); // 创建上下文对象context.request(); // 输出:当前状态为A,并切换到状态Acontext.request(); // 输出:当前状态为B,并切换到状态B}
}

1.3 使用状态模式的注意事项

  • 1、状态模式适用于当一个对象在它的状态发生改变时,它的行为也随着发生较大的变化。也就是说,在行为受状态约束的情况下可以使用状态模式。如果一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求不同行为的时候,可以考虑使用状态模式。

  • 2、状态模式的关键点在于不同的状态下对于同一行为有不同的响应。这其实就是一个将 if~else 用多态来实现的一个具体示例。

  • 3、状态模式的使用必然会增加系统类和对象的个数。尽管状态模式提供了一个更好的方法来组织与特定状态相关的代码,将繁琐的状态判断转换成结构清晰的状态类族,在避免代码膨胀的同时也保证了可扩展性与可维护性,但会增加系统的复杂性。

  • 4、当使用状态模式时,需要避免过多的状态转换,如果对象的状态太多,可能会导致系统变得复杂难以维护。最好保证对象的状态不超过5个。

  • 5、Context类应当尽可能地简单,它的职责主要是负责维护当前状态,并根据当前状态调用相应的状态处理方法。如果Context类过于复杂,可能会影响系统的可维护性和可扩展性。

二、状态模式的用途

  • 1、当一个对象的状态改变时,它的行为也随着发生较大的变化。也就是说,在行为受状态约束的情况下可以使用状态模式。如果一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求不同行为的时候,可以考虑使用状态模式。

  • 2、状态模式的关键点在于不同的状态下对于同一行为有不同的响应。这其实就是一个将 if~else 用多态来实现的一个具体示例。

  • 3、状态模式提供了一个更好的方法来组织与特定状态相关的代码,将繁琐的状态判断转换成结构清晰的状态类族,在避免代码膨胀的同时也保证了可扩展性与可维护性。

  • 4、当使用状态模式时,需要避免过多的状态转换,如果对象的状态太多,可能会导致系统变得复杂难以维护。最好保证对象的状态不超过5个。

三、状态模式实现方式

3.1 使用枚举类型实现状态模式

首先,定义一个表示状态的枚举类型:

public enum State {STATE_A,STATE_B,STATE_C
}

然后,创建一个类,该类包含一个表示当前状态的变量,并提供一个方法来更改状态:

public class StatePatternDemo {private State currentState;public StatePatternDemo() {currentState = State.STATE_A;}public void changeState(State newState) {currentState = newState;performAction();}private void performAction() {switch (currentState) {case STATE_A:System.out.println("执行状态 A 的操作");break;case STATE_B:System.out.println("执行状态 B 的操作");break;case STATE_C:System.out.println("执行状态 C 的操作");break;}}
}

最后,创建一个主类来测试状态模式:

public class Main {public static void main(String[] args) {StatePatternDemo demo = new StatePatternDemo();demo.changeState(State.STATE_B);demo.changeState(State.STATE_C);}
}

运行上述代码,将输出以下结果:

执行状态 A 的操作
执行状态 B 的操作
执行状态 C 的操作

3.2 使用内部类实现状态模式

首先,创建一个外部类 Context,它将包含一个表示当前状态的内部类 State 的实例变量。然后,为每个可能的状态创建一个内部类,这些类将实现一个共同的接口,该接口定义了所有状态都需要实现的方法。最后,在 Context 类中,提供一个方法来更改状态,并调用新状态的相应方法。

public class Context {// 内部类 State,表示状态private State state;public Context(State state) {this.state = state;}// 更改状态的方法public void setState(State state) {this.state = state;}// 执行状态操作的方法public void request() {state.handle();}
}// 定义一个接口,表示状态需要实现的方法
interface State {void handle();
}// 具体状态类 A
class StateA implements State {@Overridepublic void handle() {System.out.println("处理状态 A");}
}// 具体状态类 B
class StateB implements State {@Overridepublic void handle() {System.out.println("处理状态 B");}
}// 具体状态类 C
class StateC implements State {@Overridepublic void handle() {System.out.println("处理状态 C");}
}// 测试代码
public class Main {public static void main(String[] args) {Context context = new Context(new StateA());context.request(); // 输出:处理状态 Acontext.setState(new StateB());context.request(); // 输出:处理状态 Bcontext.setState(new StateC());context.request(); // 输出:处理状态 C}
}

在这个示例中,我们创建了一个名为 Context 的外部类,它包含一个名为 State 的内部类实例变量。我们还为每个可能的状态创建了一个内部类(StateA、StateB 和 StateC),它们都实现了一个名为 State 的接口。在 Context 类中,我们提供了一个名为 setState 的方法来更改状态,并调用新状态的 handle 方法。

3.3 使用接口实现状态模式

首先,创建一个表示状态的接口:

public interface State {void handle(Context context);
}

然后,创建具体的状态类,实现State接口:

public class ConcreteStateA implements State {@Overridepublic void handle(Context context) {System.out.println("当前状态是A");context.setState(new ConcreteStateB());}
}public class ConcreteStateB implements State {@Overridepublic void handle(Context context) {System.out.println("当前状态是B");context.setState(new ConcreteStateA());}
}

接下来,创建一个上下文类,用于存储当前状态,并实现State接口:

public class Context {private State state;public Context() {state = new ConcreteStateA();}public void setState(State state) {this.state = state;}public void request() {state.handle(this);}
}

最后,在主函数中测试状态模式:

public class StatePatternDemo {public static void main(String[] args) {Context context = new Context();context.request(); // 输出:当前状态是Acontext.request(); // 输出:当前状态是Bcontext.request(); // 输出:当前状态是A}
}

在这个示例中,我们定义了一个State接口,以及两个具体的状态类ConcreteStateA和ConcreteStateB。Context类负责存储当前状态,并在需要时切换状态。通过调用Context类的request方法,我们可以在不同状态之间进行切换。

3.4 使用抽象类实现状态模式

首先,创建一个表示状态的抽象类State:

public abstract class State {public abstract void handle(Context context);
}

然后,创建具体的状态类,例如StartState和StopState:

public class StartState extends State {@Overridepublic void handle(Context context) {System.out.println("启动状态");context.setState(new StopState());}
}public class StopState extends State {@Overridepublic void handle(Context context) {System.out.println("停止状态");context.setState(new StartState());}
}

接下来,创建一个表示上下文的类Context,并包含一个State类型的成员变量:

public class Context {private State state;public Context() {this.state = new StartState();}public void setState(State state) {this.state = state;}public void request() {state.handle(this);}
}

最后,在主函数中测试状态模式:

public class Main {public static void main(String[] args) {Context context = new Context();context.request(); // 输出:启动状态context.request(); // 输出:停止状态context.request(); // 输出:启动状态}
}

在这个示例中,我们使用抽象类State定义了状态的接口,并创建了两个具体的状态类StartState和StopState。Context类负责管理当前状态,并在需要时切换状态。通过调用context.request()方法,我们可以在不同状态之间进行切换。

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

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

相关文章

深度学习 机器视觉 人脸识别系统 - opencv python 计算机竞赛

文章目录 0 前言1 机器学习-人脸识别过程人脸检测人脸对其人脸特征向量化人脸识别 2 深度学习-人脸识别过程人脸检测人脸识别Metric Larning 3 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 深度学习 机器视觉 人脸识别系统 该项目…

从头开始的卷积神经网络

VGG-16 卷积神经网络。来源:LearnOpenCV 参考资料:这篇文章可以在 Kaggle Notebook 🧠 Convolutional Neural Network From Scratch上更好地阅读。路易斯费尔南多托雷斯 一、说明 本文详细介绍在tf2.0上,使用ceras实现基本的神经…

C++字典树算法:找出强数对的最大异或值 II

涉及知识点 数学 字典树 题目 给你一个下标从 0 开始的整数数组 nums 。如果一对整数 x 和 y 满足以下条件&#xff0c;则称其为 强数对 &#xff1a; |x - y| < min(x, y) 你需要从 nums 中选出两个整数&#xff0c;且满足&#xff1a;这两个整数可以形成一个强数对&…

linux openssl C++ md5开发实例

文章目录 一、MD5 介绍二、MD5 原理三、MD5 C开发实例四、生日冲突算法 一、MD5 介绍 MD5&#xff08;Message Digest Algorithm 5&#xff09;是一种广泛用于产生消息摘要&#xff08;哈希值&#xff09;的算法。MD5 属于 MD&#xff08;Message Digest&#xff09;家族&…

mysql主从复制-使用心得

文章目录 前言环境配置主库从库 STATEMENTbinloggtidlog-errorDistSQL总结 前言 mysql 主从复制使用感受&#xff0c;遇到一些问题的整理&#xff0c;也总结了一些排查问题技巧。 环境 mysql5.7 配置 附&#xff1a;千万级数据快速插入配置可以参考&#xff1a;mysql千万数…

HarmonyOS应用开发者高级认证(88分答案)

看好选择题&#xff0c;每个2分多答对2个刚好88分&#xff0c;祝你顺利。 其它帮扶选择题。 一、判断 只要使用端云一体化的云端资源就需要支付费用&#xff08;错&#xff09;所有使用Component修饰的自定义组件都支持onPageShow&#xff0c;onBackPress和onPageHide生命周期…

Spring-AOP不生效之内部方法调用

Spring-AOP 现象&#xff1a;接口实现类中有两个&#xff0c;doMethod1()调用了doMethod2(),此时对于AOP&#xff0c;如果现在外部对象调用doMethod1()方法的时候&#xff0c;会发现只有doMethod1()方法执行被拦截,AOP生效&#xff0c;而doMethod1()内部调用doMethod2()时并没…

vue3配置环境变量,小白简单易学

环境变量的意义就是防止我们更新打包的时候写错变量&#xff0c;合并代码这些一系列问题 首先看看效果 左边是本地测试环境&#xff0c;右边是打包后的生产环境&#xff0c;写这个环境变量的好处就是&#xff0c;你在本地开发的时候变量随便改&#xff0c;不会影响生产环境&am…

07【保姆级】-GO语言的程序流程控制【if switch for while 】

之前我学过C、Java、Python语言时总结的经验&#xff1a; 先建立整体框架&#xff0c;然后再去抠细节。先Know how&#xff0c;然后know why。先做出来&#xff0c;然后再去一点点研究&#xff0c;才会事半功倍。适当的囫囵吞枣。因为死抠某个知识点很浪费时间的。对于GO语言&a…

二十三种设计模式全面解析-组合模式与迭代器模式的结合应用:构建灵活可扩展的对象结构

在前文中&#xff0c;我们介绍了组合模式的基本原理和应用&#xff0c;以及它在构建对象结构中的价值和潜力。然而&#xff0c;组合模式的魅力远不止于此。在本文中&#xff0c;我们将继续探索组合模式的进阶应用&#xff0c;并展示它与其他设计模式的结合使用&#xff0c;以构…

2024 款:最新前端技术趋势

Hello&#xff0c;大家好&#xff0c;我是 Sunday。 上一次的时候聊了 那么些已经落后的前端开发技术 。但是光知道什么技术落后了是不够的&#xff0c;咱们还得知道 前端最新的技术趋势是什么。所以&#xff0c;今天这篇文章&#xff0c;咱们就来聊一聊&#xff0c;2023 最新…

Spring后端HttpClient实现微信小程序登录

这是微信官方提供的时序图。我们需要关注的是前后端的交互&#xff0c;以及服务端如何收发网络请求。 小程序端 封装基本网络请求 我们先封装一个基本的网络请求。 const baseUrl"localhost:8080" export default{sendRequsetAsync } /* e url&#xff1a;目标页…

对比国内主流开源 SQL 审核平台 Yearning vs Archery

Yearning, Archery 和 Bytebase 是目前国内最主流的三个开源 SQL 审核平台。其中 Yearning 和 Archery 是社区性质的项目&#xff0c;而 Bytebase 则是商业化产品。通常调研 Bytebase 的用户也会同时比较 Yearning 和 Archery。 下面我们就来展开对比一下 Yearning 和 Archery…

DRAM和SRAM

特点 Static Random Access Memory&#xff1a;速度快、存储一位需要元器件更多、功耗较大、集成度低、更贵 Dynamic Random Access Memory&#xff1a;容量大、需刷新、附属电路更复杂、功耗较小、集成度高 存储位元 SRAM DRAM 逻辑结构 SRAM 典型的SRAM芯片有6116&am…

Layer 2 真的为以太坊扩容了吗?

构建一个安全、对用户友好的去中心化网络的愿景&#xff0c;依赖于关键基础设施的发展。这个愿景由一个共享的经济框架支持&#xff0c;得到了亿万人的拥护。Layer 2 的扩展解决方案在构建这一基础和增强以太坊的能力方面起着至关重要的作用。这些项目相互协作&#xff0c;形成…

数据结构—数组栈的实现

前言&#xff1a;各位小伙伴们我们前面已经学习了带头双向循环链表&#xff0c;数据结构中还有一些特殊的线性表&#xff0c;如栈和队列&#xff0c;那么我们今天就来实现数组栈。 目录&#xff1a; 一、 栈的概念 二、 栈的实现 三、 代码测试 栈的概念&#xff1a; 栈的概念…

【nlp】1.3 文本数据分析(标签数量分布、句子长度分布、词频统计与关键词词云)

文本数据分析 1 文本数据分析介绍2 数据集说明3 获取标签数量分布4 获取句子长度分布5 获取正负样本长度散点分布6 获取不同词汇总数统计7 获取训练集高频形容词词云8 获取验证集形容词词云1 文本数据分析介绍 文本数据分析的作用: 文本数据分析能够有效帮助我们理解数据语料…

[100天算法】-不同路径 III(day 75)

题目描述 在二维网格 grid 上&#xff0c;有 4 种类型的方格&#xff1a;1 表示起始方格。且只有一个起始方格。 2 表示结束方格&#xff0c;且只有一个结束方格。 0 表示我们可以走过的空方格。 -1 表示我们无法跨越的障碍。 返回在四个方向&#xff08;上、下、左、右&#…

(selenium element not interactable)selenium的send_keys怎么往codemirror中发送数据

简直了&#xff0c;什么方法都试过了&#xff0c;什么鼠标悬停、修改js都不行。最后居然就是定位到textarea域&#xff0c;再定位到想插入文本的位置的前面&#xff08;我理解就是定位到cursor游标&#xff09;&#xff1b;然后点击以显示游标&#xff1b;最后往textarea域send…

【PG】PostgreSQL 预写日志(WAL)、checkpoint、LSN

目录 预写式日志&#xff08;WAL&#xff09; WAL概念 WAL的作用 WAL日志存放路径 WAL日志文件数量 WAL日志文件存储形式 WAL日志文件命名 WAL内容 检查点&#xff08;checkpoint&#xff09; 1 检查点概念 2 检查点作用 触发检查点 触发检查点之后数据库操作 设置合…