当前位置: 首页 > news >正文

行为模式-状态模式

定义:

        Allow an object to alter its behavior when its internal state changes.The object will appear to change its class.(当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其 类。)

状态模式通用类图

        状态设计模式的核心思想是将状态相关的行为封装到状态类中,通过状态对象的切换来实现行为的改变。它避免了在一个类中使用大量的条件语句(如if - else或switch - case)来判断不同状态下的行为,而是将每个状态的行为逻辑分散到具体的状态类中。这样,当需要增加新状态或修改现有状态的行为时,只需新增或修改对应的状态类,符合开闭原则,提高了代码的可维护性和可扩展性。

角色:

状态模式包含以下几个核心角色:

​1、环境类(Context)

        环境类是拥有状态的对象,它维护一个当前状态的引用,并且提供操作状态的方法。环境类不直接实现与状态相关的行为,而是将行为委托给当前的状态对象。环境类充当状态对象和客户端之间的桥梁,客户端通过环境类间接访问状态对象的行为。

2、抽象状态类(State)

        抽象状态类定义了一个接口,用于封装与环境类的一个状态相关的行为。它声明了所有具体状态类都必须实现的方法,这些方法对应了在该状态下环境类可能执行的操作。抽象状态类为具体状态类提供了统一的抽象,使得环境类可以以一致的方式与不同的状态对象交互。

3、具体状态类(Concrete State)

        具体状态类是抽象状态类的实现类,每个具体状态类对应环境类的一个具体状态,负责实现该状态下环境类的行为逻辑。在具体状态类中,不仅实现了抽象状态类定义的方法,还可以维护该状态特有的数据或进行状态转换的逻辑判断。

4、客户端(Client)

        客户端负责创建环境类和具体状态类的对象,并将初始状态设置到环境类中。客户端通过调用环境类的方法来触发状态相关的操作,但客户端通常不直接与具体状态类交互,而是由环境类和状态类协同完成状态管理和行为执行。

代码示例:

        假设我们要实现一个电梯的状态管理系统,电梯有 “静止”“上升”“下降”“故障” 四种状态,在不同状态下对楼层选择、开门关门等操作有不同的响应。

// 抽象状态类:电梯状态

public interface ElevatorState {void selectFloor(int floor, ElevatorContext context);void openDoor(ElevatorContext context);void closeDoor(ElevatorContext context);void emergencyStop(ElevatorContext context);}

// 具体状态类:静止状态

public class IdleState implements ElevatorState {@Overridepublic void selectFloor(int floor, ElevatorContext context) {if (floor > context.getCurrentFloor()) {context.setState(new UpState());System.out.println("电梯开始上升,前往 " + floor + " 层");} else if (floor < context.getCurrentFloor()) {context.setState(new DownState());System.out.println("电梯开始下降,前往 " + floor + " 层");} else {System.out.println("已在当前楼层");}}@Overridepublic void openDoor(ElevatorContext context) {System.out.println("电梯门打开");}@Overridepublic void closeDoor(ElevatorContext context) {System.out.println("电梯门关闭");}@Overridepublic void emergencyStop(ElevatorContext context) {context.setState(new FaultState());System.out.println("电梯发生故障,紧急停止");}}

// 具体状态类:上升状态

public class UpState implements ElevatorState {@Overridepublic void selectFloor(int floor, ElevatorContext context) {if (floor > context.getCurrentFloor()) {System.out.println("继续上升,前往 " + floor + " 层");} else if (floor < context.getCurrentFloor()) {context.setState(new DownState());System.out.println("电梯改变方向,开始下降,前往 " + floor + " 层");} else {context.setState(new IdleState());System.out.println("到达目标楼层,电梯停止");}}@Overridepublic void openDoor(ElevatorContext context) {context.setState(new IdleState());System.out.println("电梯到达楼层,门打开");}@Overridepublic void closeDoor(ElevatorContext context) {System.out.println("电梯门关闭,继续上升");}@Overridepublic void emergencyStop(ElevatorContext context) {context.setState(new FaultState());System.out.println("电梯发生故障,紧急停止");}}

// 具体状态类:下降状态

public class DownState implements ElevatorState {@Overridepublic void selectFloor(int floor, ElevatorContext context) {if (floor < context.getCurrentFloor()) {System.out.println("继续下降,前往 " + floor + " 层");} else if (floor > context.getCurrentFloor()) {context.setState(new UpState());System.out.println("电梯改变方向,开始上升,前往 " + floor + " 层");} else {context.setState(new IdleState());System.out.println("到达目标楼层,电梯停止");}}@Overridepublic void openDoor(ElevatorContext context) {context.setState(new IdleState());System.out.println("电梯到达楼层,门打开");}@Overridepublic void closeDoor(ElevatorContext context) {System.out.println("电梯门关闭,继续下降");}@Overridepublic void emergencyStop(ElevatorContext context) {context.setState(new FaultState());System.out.println("电梯发生故障,紧急停止");}}

// 具体状态类:故障状态

public class FaultState implements ElevatorState {@Overridepublic void selectFloor(int floor, ElevatorContext context) {System.out.println("电梯故障,无法选择楼层");}@Overridepublic void openDoor(ElevatorContext context) {System.out.println("电梯故障,尝试开门");}@Overridepublic void closeDoor(ElevatorContext context) {System.out.println("电梯故障,无法关门");}@Overridepublic void emergencyStop(ElevatorContext context) {System.out.println("电梯已处于故障状态");}}

// 环境类:电梯

public class ElevatorContext {private ElevatorState state;private int currentFloor;public ElevatorContext() {this.state = new IdleState();this.currentFloor = 1;}public void setState(ElevatorState state) {this.state = state;}public int getCurrentFloor() {return currentFloor;}public void setCurrentFloor(int currentFloor) {this.currentFloor = currentFloor;}public void selectFloor(int floor) {state.selectFloor(floor, this);}public void openDoor() {state.openDoor(this);}public void closeDoor() {state.closeDoor(this);}public void emergencyStop() {state.emergencyStop(this);}}

// 客户端代码

public class StatePatternClient {public static void main(String[] args) {ElevatorContext elevator = new ElevatorContext();elevator.selectFloor(5);elevator.openDoor();elevator.closeDoor();elevator.selectFloor(3);elevator.emergencyStop();}}

优点 :

1、提高代码可读性和可维护性:将不同状态下的行为逻辑封装到具体状态类中,避免了大量条件语句的嵌套,使代码结构更加清晰。当需要修改某个状态的行为或增加新状态时,只需修改或新增对应的状态类,降低了代码维护的难度。

2、符合开闭原则:新增状态或修改现有状态行为时,无需修改环境类和其他状态类的代码,只需要创建新的具体状态类或修改已有状态类,满足了开闭原则,提高了系统的扩展性。

3、便于状态管理和转换:状态设计模式将状态转换逻辑封装在状态类中,每个状态类可以清晰地定义从当前状态到其他状态的转换条件和操作,使状态转换的管理更加直观和易于控制。


缺点:

1、增加类的数量:每个状态都需要一个对应的具体状态类,当状态数量较多时,会导致系统中类的数量显著增加,增加了代码的复杂性和理解难度。

2、状态类之间的依赖关系:在某些情况下,具体状态类之间可能存在复杂的依赖关系,特别是在涉及状态转换时,可能需要在多个状态类之间进行协调,增加了代码的维护成本。

3、性能开销:由于状态设计模式引入了多个状态类和对象之间的交互,相比于简单的条件语句实现,可能会产生一定的性能开销,尤其是在频繁进行状态切换和方法调用的场景中。


使用场景: 

(一)对象行为依赖状态变化

        当一个对象的行为会根据其内部状态的不同而发生显著变化,并且状态的数量较多,使用大量条件语句判断状态会使代码变得复杂且难以维护时,适合使用状态设计模式。例如,游戏角色在不同状态(如正常、中毒、无敌)下的行为差异很大,通过状态模式可以清晰地管理这些行为。

(二)状态转换逻辑复杂

        如果对象的状态转换存在复杂的逻辑关系,不同状态之间的转换需要满足特定条件,状态设计模式可以将这些转换逻辑封装在具体状态类中,使状态转换的逻辑更加清晰易懂,便于维护和扩展。如自动售货机在 “有货”“无货”“投币”“找零” 等状态间的转换控制。

(三)代码遵循开闭原则

        当系统需要在不修改现有代码的基础上,方便地增加新的状态或修改现有状态的行为时,状态设计模式能够很好地满足这一需求。只需新增或修改具体状态类,而不会影响到环境类和其他状态类,符合开闭原则。

        状态设计模式通过将对象的状态和行为进行封装与分离,为处理对象状态变化相关的问题提供了一种优雅且高效的解决方案。它在电梯控制、订单管理、游戏开发等众多领域有着广泛的应用,能够有效提高代码的可读性、可维护性和扩展性。然而,在使用状态设计模式时,也需要权衡其带来的类数量增加、依赖关系复杂和性能开销等问题。合理运用状态设计模式,能够让我们在面对复杂的状态管理需求时,构建出更加清晰、灵活和健壮的软件系统,使代码在状态的变迁中保持优雅与高效。

http://www.lryc.cn/news/588983.html

相关文章:

  • 小智完整MCP交互流程(以调节音量为例)
  • 网络安全职业指南:探索网络安全领域的各种角色
  • 使用llama-factory进行qwen3模型微调
  • elasticsearch 下载/安装
  • MaxKB使用笔记【持续ing】
  • python+selenium UI自动化初探
  • JAVA高级第一章 集合框架和泛型(一)
  • Ubuntu18.04 系统重装记录
  • 写作词汇积累(A):自洽、自恰、恰如其分、恰当
  • MQ2烟雾传感器模块(第九天)
  • C++学习笔记五
  • 《时间简史》:窥探宇宙的奥秘
  • IOS 18下openURL 失效问题
  • 032_API参考文档
  • 前端面试专栏-工程化:25.项目亮点与技术难点梳理
  • 区块链的三种共识机制——PoW、PoS和DPoS原理
  • 数据库第二次作业
  • 【Python练习】044. 编写一个函数,实现快速排序算法
  • 本地电脑安装Dify|内网穿透到公网
  • 开源AI应用开发平台Dify系列(一)
  • YOLO融合CFFormer中的FeatureCorrection_s2c模块
  • 多租户SaaS系统中设计安全便捷的跨租户流程共享
  • 遥感数据与作物生长模型同化及在作物长势监测与估产中的应用
  • 弗兰肯斯坦式的人工智能与GTM策略的崩溃
  • 运维效率提升利器:grep、sed、awk详解与实战练习指南
  • (LeetCode 面试经典 150 题) 383. 赎金信 (哈希表)
  • AR眼镜:重塑医学教育,开启智能教学新时代
  • 配置使用SSH与VScode进行连接
  • dockerfile 最佳实践
  • 如何解决服务器频繁重启的问题?