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

Java设计模式之状态模式详解

Java设计模式之状态模式详解

在软件开发过程中,我们经常会遇到这样的情况:一个对象的行为会根据其内部状态的变化而变化。例如,电梯可能处于运行、停止、维修等不同状态,不同状态下对按钮操作的响应不同;游戏角色在正常、受伤、死亡等状态下,其动作和交互方式也有差异。对于这类问题,状态模式(State Pattern)提供了优雅的解决方案。下面将通过图文结合的方式,详细介绍Java中的状态模式。

一、状态模式概念

状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为,使对象看起来似乎修改了它的类。在状态模式中,将对象的每个状态都封装成一个独立的类,这些类实现同一个状态接口,而拥有状态的对象仅需在内部维护一个当前状态对象的引用。当对象的状态发生变化时,只需要替换当前的状态对象,对象的行为就会随之改变,从而避免了大量的条件判断语句,使代码更加清晰、易于维护和扩展。

二、状态模式结构(Mermaid类图)

使用Mermaid绘制状态模式的类图,能直观呈现各角色关系。

1
1
Context
-state: State
+request()
+setState(State state)
State
+handle(Context context)
ConcreteStateA
+handle(Context context)
ConcreteStateB
+handle(Context context)

在上述类图中:

  • Context(上下文):维护一个对State对象的引用,代表当前状态,同时提供对外的操作接口,这些操作会委托给当前的State对象来处理。
  • State(状态接口):定义了一个接口,用于封装与Context的一个状态相关的行为,所有具体状态类都要实现这个接口。
  • ConcreteState(具体状态类):实现State接口,每个具体状态类都对应Context的一个具体状态,在具体状态类中实现与该状态相关的行为逻辑。

三、Java代码示例

以自动售货机为例,售货机有“有商品”“无商品”“售出商品”等状态,不同状态下投币、退币、购买商品的操作逻辑不同。下面通过Java代码实现这个自动售货机的状态模式。

1. 定义状态接口State

public interface State {void insertCoin();void ejectCoin();void turnCrank();void dispense();
}

2. 实现具体状态类

NoQuarterState(无硬币状态)

public class NoQuarterState implements State {private VendingMachine vendingMachine;public NoQuarterState(VendingMachine vendingMachine) {this.vendingMachine = vendingMachine;}@Overridepublic void insertCoin() {System.out.println("You inserted a quarter");vendingMachine.setState(vendingMachine.getHasQuarterState());}@Overridepublic void ejectCoin() {System.out.println("You haven't inserted a quarter yet");}@Overridepublic void turnCrank() {System.out.println("You need to insert a quarter first");}@Overridepublic void dispense() {System.out.println("You need to pay first");}
}

HasQuarterState(有硬币状态)

public class HasQuarterState implements State {private VendingMachine vendingMachine;public HasQuarterState(VendingMachine vendingMachine) {this.vendingMachine = vendingMachine;}@Overridepublic void insertCoin() {System.out.println("You already inserted a quarter");}@Overridepublic void ejectCoin() {System.out.println("Quarter returned");vendingMachine.setState(vendingMachine.getNoQuarterState());}@Overridepublic void turnCrank() {System.out.println("You turned...");vendingMachine.setState(vendingMachine.getSoldState());vendingMachine.dispense();}@Overridepublic void dispense() {System.out.println("No item dispensed");}
}

SoldState(售出商品状态)

public class SoldState implements State {private VendingMachine vendingMachine;public SoldState(VendingMachine vendingMachine) {this.vendingMachine = vendingMachine;}@Overridepublic void insertCoin() {System.out.println("Please wait, we're already giving you an item");}@Overridepublic void ejectCoin() {System.out.println("Sorry, you've already turned the crank");}@Overridepublic void turnCrank() {System.out.println("Turning twice doesn't get you another item!");}@Overridepublic void dispense() {vendingMachine.releaseItem();if (vendingMachine.getCount() > 0) {vendingMachine.setState(vendingMachine.getNoQuarterState());} else {System.out.println("Oops, out of stock!");vendingMachine.setState(vendingMachine.getOutOfStockState());}}
}

OutOfStockState(无商品状态)

public class OutOfStockState implements State {private VendingMachine vendingMachine;public OutOfStockState(VendingMachine vendingMachine) {this.vendingMachine = vendingMachine;}@Overridepublic void insertCoin() {System.out.println("You can't insert a quarter, the machine is out of stock");}@Overridepublic void ejectCoin() {System.out.println("You can't eject, you haven't inserted a quarter yet");}@Overridepublic void turnCrank() {System.out.println("You turned, but there are no items");}@Overridepublic void dispense() {System.out.println("No item to dispense");}
}

3. 定义上下文类VendingMachine

public class VendingMachine {State noQuarterState;State hasQuarterState;State soldState;State outOfStockState;State state = noQuarterState;int count = 0;public VendingMachine(int count) {this.count = count;noQuarterState = new NoQuarterState(this);hasQuarterState = new HasQuarterState(this);soldState = new SoldState(this);outOfStockState = new OutOfStockState(this);}public void insertCoin() {state.insertCoin();}public void ejectCoin() {state.ejectCoin();}public void turnCrank() {state.turnCrank();state.dispense();}void setState(State state) {this.state = state;}void releaseItem() {System.out.println("A gumball comes rolling out the slot...");if (count > 0) {count = count - 1;}}public State getNoQuarterState() {return noQuarterState;}public State getHasQuarterState() {return hasQuarterState;}public State getSoldState() {return soldState;}public State getOutOfStockState() {return outOfStockState;}public int getCount() {return count;}
}

4. 测试代码

public class VendingMachineTest {public static void main(String[] args) {VendingMachine vendingMachine = new VendingMachine(10);vendingMachine.insertCoin();vendingMachine.turnCrank();vendingMachine.ejectCoin();vendingMachine.insertCoin();vendingMachine.insertCoin();vendingMachine.turnCrank();for (int i = 0; i < 11; i++) {vendingMachine.turnCrank();}}
}

在上述代码中:

  • State接口定义了自动售货机在不同状态下可执行的操作方法。
  • 各个具体状态类(如NoQuarterStateHasQuarterState等)实现State接口,在其中编写对应状态下的操作逻辑,并在适当时候切换售货机的状态。
  • VendingMachine类作为上下文,持有所有具体状态类的实例,对外提供操作接口,将操作委托给当前状态对象处理,同时可以根据业务逻辑切换状态。
  • VendingMachineTest类用于测试自动售货机在不同操作下的状态变化和行为表现。

四、状态模式的优缺点

优点

  1. 清晰的逻辑分离:将不同状态下的行为逻辑封装在独立的状态类中,避免了大量的条件判断语句(如if-elseswitch-case),使代码结构更加清晰,易于理解和维护。
  2. 扩展性强:当需要增加新的状态时,只需要新增一个具体状态类并实现状态接口即可,不需要修改上下文类和其他状态类的代码,符合开闭原则。
  3. 可维护性高:由于每个状态类都专注于处理一种状态的行为,修改某个状态的行为逻辑时,只需要修改对应的状态类,不会影响其他状态的逻辑,降低了代码的耦合度。

缺点

  1. 类数量增加:每个具体状态都需要一个独立的类来实现,当状态较多时,会导致类的数量急剧增加,增加了系统的复杂性和维护成本。
  2. 状态转换的复杂性:在某些情况下,状态之间的转换规则可能比较复杂,需要仔细处理状态之间的转换逻辑,否则可能会出现状态混乱的问题。

五、应用场景

  1. 工作流系统:在工作流系统中,任务可能处于不同的状态,如“待处理”“处理中”“已完成”“已驳回”等,不同状态下对任务的操作(如提交、审批、退回等)逻辑不同,使用状态模式可以很好地管理这些状态和对应的操作。
  2. 游戏开发:游戏角色、游戏场景等往往存在多种状态,例如游戏角色的攻击、防御、跳跃、奔跑等状态,每个状态下的行为和动画效果不同,状态模式可以有效组织这些状态相关的逻辑。
  3. 设备状态管理:像打印机、路由器等设备,会有“就绪”“打印中”“故障”“离线”等状态,不同状态下对设备的操作响应不同,通过状态模式可以清晰地实现设备的状态管理和行为控制。

相关文章:

  • Unity基础-数学向量
  • NY118NY120美光固态闪存NY124NY129
  • 高股息打底+政策催化增强+永续经营兜底
  • 每日算法 -【Swift 算法】电话号码字母组合
  • CSS6404L 在物联网设备中的应用优势:低功耗高可靠的存储革新与竞品对比
  • 本机无法远程别的计算机的方法
  • MySQL查询语句(续)
  • C++.OpenGL (1/64) 创建窗口(Hello Window)
  • python八股文算法:三数之和
  • GIT(AI回答)
  • JS面试常见问题——数据类型篇
  • 传输层:udp与tcp协议
  • 【递归、搜索与回溯】专题三 穷举vs暴搜vs回溯vs剪枝
  • Python获取网易云音乐的评论
  • Java-前置基础
  • Kafka 入门指南与一键部署
  • S5P6818_驱动篇(24)UART驱动
  • IoT/HCIP实验-4/单片机基础实验(LCD/LED/按键操作/GPIO/EXTI中断服务)
  • untiy 模拟人物在街道走路和跑步
  • Java中==和equals的区别
  • 网站建设验收合格确认书/百度搜索量统计
  • 企业类网站包括哪些/排名第一的手机清理软件
  • 网站免费正能量软件/seo实战培训教程
  • 网站如何进行代码优化/友情链接怎么购买
  • 用自己头像做的圣诞视频网站/下拉关键词排名
  • wordpress调用分类文章排序/seo资料站