Java状态模式的应用示例
2024-03-284.2k 阅读
Java 状态模式的概念与原理
状态模式的定义
状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。这种模式将状态封装成独立的类,并将请求委托给当前的状态对象,使得对象的行为可以根据其状态动态地改变。
状态模式的结构
- 环境(Context):持有一个状态对象的引用,定义客户端感兴趣的接口,并将与状态相关的操作委托给当前的状态对象处理。
- 抽象状态(State):定义一个接口,封装与环境的一个特定状态相关的行为。
- 具体状态(ConcreteState):实现抽象状态定义的接口,每个具体状态类对应环境的一个状态,实现与该状态相关的行为。
状态模式的优势
- 可维护性:将不同状态的行为封装在不同的类中,当需要修改某个状态的行为时,只需要修改对应的具体状态类,不会影响其他状态类。
- 可扩展性:增加新的状态非常容易,只需要创建一个新的具体状态类并实现抽象状态接口即可。
- 清晰的状态管理:状态模式使得状态转换和状态相关的行为变得清晰明了,提高了代码的可读性。
Java 状态模式的简单示例
场景描述
假设我们有一个自动售货机,它有不同的状态,如“有商品”、“无商品”、“投币”、“出货”等。当售货机处于不同状态时,对投币、退币、出货等操作的响应是不同的。
代码实现
- 抽象状态类
abstract class VendingMachineState {
protected VendingMachine vendingMachine;
public VendingMachineState(VendingMachine vendingMachine) {
this.vendingMachine = vendingMachine;
}
public abstract void insertCoin();
public abstract void ejectCoin();
public abstract void dispense();
}
- 具体状态类 - 有商品状态
class HasProductState extends VendingMachineState {
public HasProductState(VendingMachine vendingMachine) {
super(vendingMachine);
}
@Override
public void insertCoin() {
System.out.println("已经投币,等待出货。");
vendingMachine.setState(vendingMachine.getDispensingState());
}
@Override
public void ejectCoin() {
System.out.println("退币成功。");
vendingMachine.setState(vendingMachine.getNoCoinState());
}
@Override
public void dispense() {
System.out.println("请先投币。");
}
}
- 具体状态类 - 无商品状态
class NoProductState extends VendingMachineState {
public NoProductState(VendingMachine vendingMachine) {
super(vendingMachine);
}
@Override
public void insertCoin() {
System.out.println("无商品,投币无效。");
}
@Override
public void ejectCoin() {
System.out.println("无商品,无法退币。");
}
@Override
public void dispense() {
System.out.println("无商品,无法出货。");
}
}
- 具体状态类 - 投币状态
class HasCoinState extends VendingMachineState {
public HasCoinState(VendingMachine vendingMachine) {
super(vendingMachine);
}
@Override
public void insertCoin() {
System.out.println("已经投币,无需重复投币。");
}
@Override
public void ejectCoin() {
System.out.println("退币成功。");
vendingMachine.setState(vendingMachine.getNoCoinState());
}
@Override
public void dispense() {
System.out.println("出货成功。");
vendingMachine.setState(vendingMachine.getNoCoinState());
if (vendingMachine.getProductCount() > 0) {
vendingMachine.setProductCount(vendingMachine.getProductCount() - 1);
if (vendingMachine.getProductCount() == 0) {
vendingMachine.setState(vendingMachine.getNoProductState());
}
}
}
}
- 具体状态类 - 出货状态
class DispensingState extends VendingMachineState {
public DispensingState(VendingMachine vendingMachine) {
super(vendingMachine);
}
@Override
public void insertCoin() {
System.out.println("正在出货,请勿投币。");
}
@Override
public void ejectCoin() {
System.out.println("正在出货,无法退币。");
}
@Override
public void dispense() {
System.out.println("出货中...");
vendingMachine.setState(vendingMachine.getHasCoinState());
}
}
- 环境类 - 自动售货机
class VendingMachine {
private int productCount;
private VendingMachineState noCoinState;
private VendingMachineState hasCoinState;
private VendingMachineState noProductState;
private VendingMachineState dispensingState;
private VendingMachineState currentState;
public VendingMachine(int productCount) {
this.productCount = productCount;
noCoinState = new NoCoinState(this);
hasCoinState = new HasCoinState(this);
noProductState = new NoProductState(this);
dispensingState = new DispensingState(this);
if (productCount > 0) {
currentState = noCoinState;
} else {
currentState = noProductState;
}
}
public void insertCoin() {
currentState.insertCoin();
}
public void ejectCoin() {
currentState.ejectCoin();
}
public void dispense() {
currentState.dispense();
}
public void setState(VendingMachineState state) {
this.currentState = state;
}
public VendingMachineState getNoCoinState() {
return noCoinState;
}
public VendingMachineState getHasCoinState() {
return hasCoinState;
}
public VendingMachineState getNoProductState() {
return noProductState;
}
public VendingMachineState getDispensingState() {
return dispensingState;
}
public int getProductCount() {
return productCount;
}
public void setProductCount(int productCount) {
this.productCount = productCount;
}
}
- 测试类
public class VendingMachineTest {
public static void main(String[] args) {
VendingMachine vendingMachine = new VendingMachine(1);
vendingMachine.insertCoin();
vendingMachine.dispense();
vendingMachine.ejectCoin();
vendingMachine.insertCoin();
vendingMachine.dispense();
}
}
在实际项目中的应用
工作流系统
在工作流系统中,一个任务可能有不同的状态,如“新建”、“待审批”、“审批通过”、“审批拒绝”等。不同状态下,任务对操作(如提交审批、重新提交、关闭任务等)的响应不同。
- 抽象状态类
abstract class TaskState {
protected Task task;
public TaskState(Task task) {
this.task = task;
}
public abstract void submitForApproval();
public abstract void resubmit();
public abstract void closeTask();
}
- 具体状态类 - 新建状态
class NewTaskState extends TaskState {
public NewTaskState(Task task) {
super(task);
}
@Override
public void submitForApproval() {
System.out.println("任务已提交审批。");
task.setState(task.getPendingApprovalState());
}
@Override
public void resubmit() {
System.out.println("任务尚未提交,无需重新提交。");
}
@Override
public void closeTask() {
System.out.println("任务已关闭。");
task.setState(task.getClosedTaskState());
}
}
- 具体状态类 - 待审批状态
class PendingApprovalState extends TaskState {
public PendingApprovalState(Task task) {
super(task);
}
@Override
public void submitForApproval() {
System.out.println("任务已在审批中,无需再次提交。");
}
@Override
public void resubmit() {
System.out.println("请先等待审批结果。");
}
@Override
public void closeTask() {
System.out.println("无法关闭待审批任务。");
}
}
- 具体状态类 - 审批通过状态
class ApprovedTaskState extends TaskState {
public ApprovedTaskState(Task task) {
super(task);
}
@Override
public void submitForApproval() {
System.out.println("任务已通过审批,无需再次提交。");
}
@Override
public void resubmit() {
System.out.println("任务已通过审批,无需重新提交。");
}
@Override
public void closeTask() {
System.out.println("任务已关闭。");
task.setState(task.getClosedTaskState());
}
}
- 具体状态类 - 审批拒绝状态
class RejectedTaskState extends TaskState {
public RejectedTaskState(Task task) {
super(task);
}
@Override
public void submitForApproval() {
System.out.println("请先修改任务后重新提交。");
}
@Override
public void resubmit() {
System.out.println("任务重新提交。");
task.setState(task.getPendingApprovalState());
}
@Override
public void closeTask() {
System.out.println("任务已关闭。");
task.setState(task.getClosedTaskState());
}
}
- 具体状态类 - 关闭状态
class ClosedTaskState extends TaskState {
public ClosedTaskState(Task task) {
super(task);
}
@Override
public void submitForApproval() {
System.out.println("已关闭任务,无法提交审批。");
}
@Override
public void resubmit() {
System.out.println("已关闭任务,无法重新提交。");
}
@Override
public void closeTask() {
System.out.println("任务已关闭。");
}
}
- 环境类 - 任务
class Task {
private TaskState newTaskState;
private TaskState pendingApprovalState;
private TaskState approvedTaskState;
private TaskState rejectedTaskState;
private TaskState closedTaskState;
private TaskState currentState;
public Task() {
newTaskState = new NewTaskState(this);
pendingApprovalState = new PendingApprovalState(this);
approvedTaskState = new ApprovedTaskState(this);
rejectedTaskState = new RejectedTaskState(this);
closedTaskState = new ClosedTaskState(this);
currentState = newTaskState;
}
public void submitForApproval() {
currentState.submitForApproval();
}
public void resubmit() {
currentState.resubmit();
}
public void closeTask() {
currentState.closeTask();
}
public void setState(TaskState state) {
this.currentState = state;
}
public TaskState getNewTaskState() {
return newTaskState;
}
public TaskState getPendingApprovalState() {
return pendingApprovalState;
}
public TaskState getApprovedTaskState() {
return approvedTaskState;
}
public TaskState getRejectedTaskState() {
return rejectedTaskState;
}
public TaskState getClosedTaskState() {
return closedTaskState;
}
}
- 测试类
public class TaskTest {
public static void main(String[] args) {
Task task = new Task();
task.submitForApproval();
task.resubmit();
task.closeTask();
}
}
游戏角色状态管理
在游戏开发中,游戏角色可能有不同的状态,如“站立”、“行走”、“跳跃”、“攻击”等。不同状态下,角色对输入(如按键操作)的响应不同。
- 抽象状态类
abstract class CharacterState {
protected GameCharacter character;
public CharacterState(GameCharacter character) {
this.character = character;
}
public abstract void handleInput(String input);
}
- 具体状态类 - 站立状态
class StandingState extends CharacterState {
public StandingState(GameCharacter character) {
super(character);
}
@Override
public void handleInput(String input) {
if ("WALK".equals(input)) {
System.out.println("角色开始行走。");
character.setState(character.getWalkingState());
} else if ("JUMP".equals(input)) {
System.out.println("角色跳跃。");
character.setState(character.getJumpingState());
} else if ("ATTACK".equals(input)) {
System.out.println("角色攻击。");
character.setState(character.getAttackingState());
}
}
}
- 具体状态类 - 行走状态
class WalkingState extends CharacterState {
public WalkingState(GameCharacter character) {
super(character);
}
@Override
public void handleInput(String input) {
if ("STOP".equals(input)) {
System.out.println("角色停止行走,进入站立状态。");
character.setState(character.getStandingState());
} else if ("JUMP".equals(input)) {
System.out.println("角色边行走边跳跃。");
character.setState(character.getJumpingState());
} else if ("ATTACK".equals(input)) {
System.out.println("角色在行走中攻击。");
character.setState(character.getAttackingState());
}
}
}
- 具体状态类 - 跳跃状态
class JumpingState extends CharacterState {
public JumpingState(GameCharacter character) {
super(character);
}
@Override
public void handleInput(String input) {
if ("LAND".equals(input)) {
System.out.println("角色落地,进入站立状态。");
character.setState(character.getStandingState());
}
}
}
- 具体状态类 - 攻击状态
class AttackingState extends CharacterState {
public AttackingState(GameCharacter character) {
super(character);
}
@Override
public void handleInput(String input) {
if ("END_ATTACK".equals(input)) {
System.out.println("攻击结束,进入站立状态。");
character.setState(character.getStandingState());
}
}
}
- 环境类 - 游戏角色
class GameCharacter {
private CharacterState standingState;
private CharacterState walkingState;
private CharacterState jumpingState;
private CharacterState attackingState;
private CharacterState currentState;
public GameCharacter() {
standingState = new StandingState(this);
walkingState = new WalkingState(this);
jumpingState = new JumpingState(this);
attackingState = new AttackingState(this);
currentState = standingState;
}
public void handleInput(String input) {
currentState.handleInput(input);
}
public void setState(CharacterState state) {
this.currentState = state;
}
public CharacterState getStandingState() {
return standingState;
}
public CharacterState getWalkingState() {
return walkingState;
}
public CharacterState getJumpingState() {
return jumpingState;
}
public CharacterState getAttackingState() {
return attackingState;
}
}
- 测试类
public class GameCharacterTest {
public static void main(String[] args) {
GameCharacter character = new GameCharacter();
character.handleInput("WALK");
character.handleInput("JUMP");
character.handleInput("LAND");
character.handleInput("ATTACK");
character.handleInput("END_ATTACK");
}
}
状态模式与其他设计模式的关系
状态模式与策略模式
- 相似点:状态模式和策略模式都涉及到通过委托来实现行为的替换。在策略模式中,不同的策略类封装了不同的算法,而在状态模式中,不同的状态类封装了不同状态下的行为。
- 不同点:策略模式中,客户端通常主动选择使用哪个策略,而状态模式中,状态的转换通常是由环境对象内部根据一定的条件自动进行的。策略模式更侧重于算法的替换,而状态模式更侧重于对象状态变化导致的行为变化。
状态模式与状态机
- 联系:状态模式可以看作是实现状态机的一种方式。状态机定义了状态、状态转换以及状态相关的行为,而状态模式通过代码实现了这些概念,将状态封装成类,并处理状态之间的转换和行为。
- 区别:状态机更侧重于抽象的概念和模型,而状态模式是一种具体的设计模式实现。状态模式提供了一种面向对象的方式来实现状态机,使得代码更加清晰和可维护。
状态模式在框架中的应用
Spring State Machine
Spring State Machine 是 Spring 框架中的一个模块,用于实现状态机。它基于状态模式,提供了一种声明式和编程式的方式来定义和管理状态机。
- 依赖引入
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-core</artifactId>
<version>2.5.2</version>
</dependency>
- 状态机配置
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.statemachine.config.EnableStateMachine;
import org.springframework.statemachine.config.EnumStateMachineConfigurerAdapter;
import org.springframework.statemachine.config.builders.StateMachineConfigurationConfigurer;
import org.springframework.statemachine.config.builders.StateMachineStateConfigurer;
import org.springframework.statemachine.config.builders.StateMachineTransitionConfigurer;
import org.springframework.statemachine.guard.Guard;
import org.springframework.statemachine.listener.StateMachineListener;
import org.springframework.statemachine.listener.StateMachineListenerAdapter;
import org.springframework.statemachine.state.State;
import java.util.EnumSet;
@Configuration
@EnableStateMachine
public class OrderStateMachineConfig extends EnumStateMachineConfigurerAdapter<OrderStates, OrderEvents> {
@Override
public void configure(StateMachineStateConfigurer<OrderStates, OrderEvents> states) throws Exception {
states.withStates()
.initial(OrderStates.NEW)
.states(EnumSet.allOf(OrderStates.class));
}
@Override
public void configure(StateMachineTransitionConfigurer<OrderStates, OrderEvents> transitions) throws Exception {
transitions.withExternal()
.source(OrderStates.NEW).target(OrderStates.PENDING)
.event(OrderEvents.SUBMIT)
.and()
.withExternal()
.source(OrderStates.PENDING).target(OrderStates.APPROVED)
.event(OrderEvents.APPROVE)
.guard(approvalGuard())
.and()
.withExternal()
.source(OrderStates.PENDING).target(OrderStates.REJECTED)
.event(OrderEvents.REJECT);
}
@Override
public void configure(StateMachineConfigurationConfigurer<OrderStates, OrderEvents> config) throws Exception {
StateMachineListener<OrderStates, OrderEvents> listener = new StateMachineListenerAdapter<>() {
@Override
public void stateChanged(State<OrderStates, OrderEvents> from, State<OrderStates, OrderEvents> to) {
System.out.println("Order state changed from " + from.getId() + " to " + to.getId());
}
};
config.withConfiguration()
.listener(listener);
}
@Bean
public Guard<OrderStates, OrderEvents> approvalGuard() {
return context -> {
// 这里可以添加审批通过的条件逻辑
return true;
};
}
}
- 状态和事件枚举
public enum OrderStates {
NEW, PENDING, APPROVED, REJECTED
}
public enum OrderEvents {
SUBMIT, APPROVE, REJECT
}
- 使用状态机
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.statemachine.StateMachine;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
@Autowired
private StateMachine<OrderStates, OrderEvents> stateMachine;
public void submitOrder() {
sendEvent(OrderEvents.SUBMIT);
}
public void approveOrder() {
sendEvent(OrderEvents.APPROVE);
}
public void rejectOrder() {
sendEvent(OrderEvents.REJECT);
}
private void sendEvent(OrderEvents event) {
Message<OrderEvents> message = MessageBuilder.withPayload(event).build();
stateMachine.sendEvent(message);
}
}
Struts 2 的状态管理
在 Struts 2 框架中,虽然没有直接使用状态模式,但在处理不同请求状态和页面流转时,体现了类似状态模式的思想。例如,Struts 2 的 Action 可以看作是环境对象,不同的结果类型(如“success”、“error”等)可以看作是不同的状态,而 Action 执行后的结果跳转类似于状态的转换。
- Struts 2 配置文件
<package name="default" namespace="/" extends="struts-default">
<action name="login" class="com.example.LoginAction" method="execute">
<result name="success">/success.jsp</result>
<result name="error">/error.jsp</result>
</action>
</package>
- Action 类
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
@Override
public String execute() throws Exception {
// 这里进行登录逻辑判断
if (isLoginSuccess()) {
return SUCCESS;
} else {
return ERROR;
}
}
private boolean isLoginSuccess() {
// 实际的登录验证逻辑
return true;
}
}
通过以上示例和分析,我们可以看到 Java 状态模式在不同场景下的应用,它为我们提供了一种有效的方式来管理对象的状态和行为,提高代码的可维护性和可扩展性。无论是简单的业务场景还是复杂的框架实现,状态模式都能发挥其独特的优势。