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

状态设计模式

状态设计模式是一种行为设计模式,它允许对象在其内部状态更改时更改其行为,就像它在运行时切换到不同的类一样。

它在以下情况下特别有用:
对象可以处于许多不同状态之一,每种状态都有不同的行为。
对象的行为取决于当前上下文,并且该上下文会随着时间的推移而变化。
你希望避免检查每个可能状态的大型、整体式或语句。if-elseswitch
当面对这种情况时,开发人员通常首先在类中使用条件逻辑来切换基于状态变量的行为。

例如,类 可能会使用 块来确定要执行的作,具体取决于它是处于“草稿”、“审阅”还是“已发布”状态。Documentif-else

但随着状态数量的增长,这种方法变得难以扩展、难以测试,并且违反了开放/封闭原则——任何新状态都需要修改现有逻辑,从而增加了破坏当前功能的风险。

状态模式通过将每个状态封装到自己的类中,并让上下文对象将行为委托给当前状态对象来解决这个问题。这使您的代码更易于扩展、重用和维护,而不会因条件而使核心逻辑变得混乱。

让我们通过一个真实世界的示例来了解如何应用状态模式以干净、可扩展和面向对象的方式管理动态行为。

问题:管理自动售货机状态
想象一下,您正在构建一个简单的自动售货机系统。从表面上看,这似乎是一项简单的任务:接受资金,分配产品,然后回到闲置状态。

但在幕后,机器的行为需要根据其当前状态而变化。

在任何给定时间,自动售货机只能处于一种状态,例如:
IdleState – 等待用户输入(未选择任何内容,未插入任何资金)。
ItemSelectedState – 已选择项目,等待付款。
HasMoneyState – 已插入资金,等待分配所选项目。
DispensingState – 机器正在主动分配项目。

该机器支持一些面向用户的作:
selectItem(String itemCode)– 选择要购买的商品
insertCoin(double amount)– 插入所选项目的付款
dispenseItem()– 触发物品分配过程
这些方法中的每一种都应根据计算机的当前状态以不同的方式运行。

例如:
在 机器打开时 调用(未选择任何项目,未插入任何资金)不应执行任何作或显示错误。dispenseItem()IdleState
在选择项目之前调用可能会被禁止或排队。insertCoin()
应 忽略或推迟期间调用,直到项目被分配。selectItem()DispensingState

天真的方法
一种常见但有缺陷的方法是 使用 or 语句在整体类中手动管理状态转换:VendingMachineif-elseswitch

public class VendingMachine {private enum State {IDLE, ITEM_SELECTED, HAS_MONEY, DISPENSING}private State currentState = State.IDLE;private String selectedItem = "";private double insertedAmount = 0.0;public void selectItem(String itemCode) {switch (currentState) {case IDLE:selectedItem = itemCode;currentState = State.ITEM_SELECTED;break;case ITEM_SELECTED:System.out.println("Item already selected");break;case HAS_MONEY:System.out.println("Payment already received for item");break;case DISPENSING:System.out.println("Currently dispensing");break;}}public void insertCoin(double amount) {switch (currentState) {case IDLE:System.out.println("No item selected");break;case ITEM_SELECTED:insertedAmount = amount;System.out.println("Inserted $" + amount + " for item");currentState = State.HAS_MONEY;break;case HAS_MONEY:System.out.println("Money already inserted");break;case DISPENSING:System.out.println("Currently dispensing");break;}}public void dispenseItem() {switch (currentState) {case IDLE:System.out.println("No item selected");break;case ITEM_SELECTED:System.out.println("Please insert coin first");break;case HAS_MONEY:System.out.println("Dispensing item '" + selectedItem);currentState = State.DISPENSING;// Simulate delay and completiontry {Thread.sleep(1000);} catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Item dispensed successfully.");resetMachine();break;case DISPENSING:System.out.println("Already dispensing. Please wait.");break;}}private void resetMachine() {selectedItem = "";insertedAmount = 0.0;currentState = State.IDLE;}
}

这种方法有什么问题?
虽然使用 with 语句适用于小型、可预测的系统,但这种方法不能很好地扩展。enumswitch

  1. 1. 代码混乱
    所有与状态相关的逻辑都塞进一个类 () 中,导致每个方法( 、 、 等)都出现大而重复的块。VendingMachineswitchif-elseselectItem()insertCoin()dispenseItem()

这导致:
难以阅读和推理的代码
跨多个方法重复检查状态
多个开发人员接触同一文件时的逻辑脆弱

  1. 2. 难以扩展
    假设你想引入新的状态,例如:
    OutOfStockState– 当所选商品售罄时
    MaintenanceState– 机器正在维修时
    要支持这些,您需要:
    更新 每个方法中的每个开关块
    在多个位置添加逻辑
    破坏现有功能的风险
    这违反了开放/封闭原则——当系统应该开放扩展时,系统可以进行修改。
  2. 3. 违反单一责任原则
    该 班现在负责:VendingMachine
    管理状态转换
    实施业务规则
    执行特定于状态的逻辑
    这种紧密耦合使该类成为单片、难以测试且耐变化。

我们真正需要什么
我们需要将与每个状态关联的行为封装到它自己的类中——这样自动售货机就可以将工作委托给当前状态对象,而不是在内部管理它。

这将使我们能够:
避免疯狂的开关情况
添加或删除状态而不修改核心类
保持每个状态的逻辑隔离和可重用
这正是状态设计模式所实现的。

状态模式
State 模式允许对象(Context)在其内部状态更改时更改其行为。该对象似乎更改了其类,因为它的行为现在已委托给不同的状态对象。

状态模式不是将特定于状态的行为嵌入上下文类本身,而是将该行为提取到单独的类中,每个类代表一个不同的状态。上下文对象保存对状态对象的引用,并将其作委托给它。

这会产生更干净、更模块化和可扩展的代码。
定义一个 State 接口(或抽象类),该接口声明表示 Context 可以执行的作的方法。
创建 ConcreteState 类,每个类都实现 State 接口。每个 ConcreteState 类都实现特定于 Context 的特定状态的行为。
Context类维护定义其当前状态的ConcreteState子类的实例。
在 Context 上调用作时,它会将该作委托给其当前 State 对象。
ConcreteState 对象通常负责将 Context 转换为新状态。

类图

 

  1. 1. 状态接口(例如MachineState)
    声明与上下文支持的作相对应的方法(例如,, ,)。selectItem()insertCoin()dispenseItem()
    这些方法通常将上下文作为参数,因此状态可以触发转换或作上下文数据。
    作为所有具体状态的共同合同。
  2. 2. 具体状态(例如, IdleStateItemSelectedState)
    实现接口 。State
    为 每个作定义特定于状态的行为。
    通常负责 在发生特定作时将上下文转换为另一种状态。
    还可以包括特定于状态的逻辑(例如,验证、消息传递)。
  3. 3. 上下文(例如VendingMachine)
    维护对当前对象的引用 。State
    定义每个作(、 等)的方法。selectItem()insertCoin()
    委托对当前状态的调用 — 状态对象处理逻辑。
    提供一种方法,例如允许状态之间的转换。setState()

实现状态模式
我们将应用状态模式来分离关注点,并使自动售货机更易于管理和扩展,而不是使用 or 语句将状态转换和行为硬编码为单个整体类。if-elseswitch

第一步是定义一个 接口,用于声明自动售货机支持的所有作。MachineState

  1. 1. 定义状态接口
    该接口表示所有州都必须遵循的契约。它声明与自动售货机面向用户的作相对应的方法。
public interface MachineState {void selectItem(VendingMachine context, String itemCode);void insertCoin(VendingMachine context, double amount);void dispenseItem(VendingMachine context);
}

每个状态都将实现此接口,定义自动售货机在该状态下的行为方式。

  1. 2. 实现具体状态类
    每个状态类将实现 接口并为每个作定义其行为。MachineState

🟡 空闲状态

public class IdleState implements MachineState {@Overridepublic void selectItem(VendingMachine context, String itemCode) {System.out.println("Item selected: " + itemCode);context.setSelectedItem(itemCode);context.setState(new ItemSelectedState());}@Overridepublic void insertCoin(VendingMachine context, double amount) {System.out.println("Please select an item before inserting coins.");}@Overridepublic void dispenseItem(VendingMachine context) {System.out.println("No item selected. Nothing to dispense.");}
}

🟠 ItemSelected状态

public class ItemSelectedState implements MachineState {@Overridepublic void selectItem(VendingMachine context, String itemCode) {System.out.println("Item already selected: " + context.getSelectedItem());}@Overridepublic void insertCoin(VendingMachine context, double amount) {System.out.println("Inserted $" + amount + " for item: " + context.getSelectedItem());context.setInsertedAmount(amount);context.setState(new HasMoneyState());}@Overridepublic void dispenseItem(VendingMachine context) {System.out.println("Insert coin before dispensing.");}
}

🟢 有钱州

public class HasMoneyState implements MachineState {@Overridepublic void selectItem(VendingMachine context, String itemCode) {System.out.println("Cannot change item after inserting money.");}@Overridepublic void insertCoin(VendingMachine context, double amount) {System.out.println("Money already inserted.");}@Overridepublic void dispenseItem(VendingMachine context) {System.out.println("Dispensing item: " + context.getSelectedItem());context.setState(new DispensingState());// Simulate dispensingtry { Thread.sleep(1000); } catch (InterruptedException e) {Thread.currentThread().interrupt();}System.out.println("Item dispensed successfully.");context.reset();}
}

🔵 分配状态

public class DispensingState implements MachineState {@Overridepublic void selectItem(VendingMachine context, String itemCode) {System.out.println("Please wait, dispensing in progress.");}@Overridepublic void insertCoin(VendingMachine context, double amount) {System.out.println("Please wait, dispensing in progress.");}@Overridepublic void dispenseItem(VendingMachine context) {System.out.println("Already dispensing. Please wait.");}
}
  1. 3. 实现上下文 (VendingMachine)
    类(我们的上下文)将维护对当前状态的引用,并将所有作委托给它。VendingMachine
public class VendingMachine {private MachineState currentState;private String selectedItem;private double insertedAmount;public VendingMachine() {this.currentState = new IdleState(); // Initial state}public void setState(MachineState newState) {this.currentState = newState;}public void setSelectedItem(String itemCode) {this.selectedItem = itemCode;}public void setInsertedAmount(double amount) {this.insertedAmount = amount;}public String getSelectedItem() {return selectedItem;}public double getInsertedAmount() {return insertedAmount;}public void selectItem(String itemCode) {currentState.selectItem(this, itemCode);}public void insertCoin(double amount) {currentState.insertCoin(this, amount);}public void dispenseItem() {currentState.dispenseItem(this);}public void reset() {this.selectedItem = "";this.insertedAmount = 0.0;this.currentState = new IdleState();}
}

客户端代码

public class VendingMachineApp {public static void main(String[] args) {VendingMachine vm = new VendingMachine();vm.insertCoin(1.0); // Invalid in IdleStatevm.selectItem("A1");vm.insertCoin(1.5);vm.dispenseItem();System.out.println("\n--- Second Transaction ---");vm.selectItem("B2");vm.insertCoin(2.0);vm.dispenseItem();}
}

通过使用状态模式,我们将僵化的、条件密集的实现转变为一个干净、灵活的架构,其中行为和转换被明确定义、解耦且易于维护。

http://www.dtcms.com/a/353414.html

相关文章:

  • 手机冻结技术发展时间轴
  • Flutter项目详解
  • 深度学习实战117-各种大模型(Qwen,MathGPT,Deepseek等)解高考数学题的应用,介绍架构原理
  • C++工程实战入门笔记6-函数(三)关于base16编码的原理和函数模块化实战
  • LINUX --- 网络编程(二)
  • OpenAi在中国拿下“GPT”商标初审!
  • October 2019 Twice SQL Injection
  • Qt图片上传系统的设计与实现:从客户端到服务器的完整方案
  • 对比视频处理单元(VPU)、图形处理器(GPU)与中央处理器(CPU)
  • 多模态模型如何处理和理解图片
  • PPT处理控件Aspose.Slides教程:在.NET中开发SVG到EMF的转换器
  • STM32学习日记
  • 替身演员的艺术:pytest-mock 从入门到飙戏
  • Java基础 8.27
  • 如何使用windows实现与iphone的隔空投送(AirDrop)
  • 【Docker基础】Docker-compose数据持久化与卷管理:深入解析docker volume命令集
  • 【重学MySQL】八十九、窗口函数的分类和使用
  • Mysql杂志(三)
  • 【46页PPT】公司数字化转型规划与实践(附下载方式)
  • 学习Python中Selenium模块的基本用法(7:元素操作-1)
  • 应变片与分布式光纤传感:核心差异与选型指南
  • 极海发布APM32F425/427系列高性能MCU:助力工业应用升级
  • laravel学习并连接mysql数据库
  • Linux 软件编程(十二)网络编程:TCP 并发服务器构建与 IO 多路复用
  • redis---set详解
  • Tortoisegit配置ssh教程
  • Vue3 新特性 defineModel 全面解析:让 v-model 写法更优雅
  • 项目智能家居---OrangePi全志H616
  • GitHub 宕机自救指南:保障开发工作连续性
  • 蓝桥杯算法之基础知识(3)——Python的idle的快捷键设置(idle改键)