文章目录
- [状态模式(State Pattern)](#状态模式(State Pattern))
- 核心原理
- [Java 实践示例](#Java 实践示例)
- 状态模式的特点
- 与策略模式的区别:
- 状态模式的应用场景
状态模式(State Pattern)
状态模式是 23 种设计模式中的一种行为型模式,其核心思想是允许对象在内部状态改变时改变它的行为,使对象看起来好像修改了它的类。这种模式将对象的状态封装为独立的状态类,通过状态切换实现行为的动态变化,避免了使用大量条件判断语句(如if-else或switch-case)。
核心原理
环境类(Context):
持有当前状态的引用,是状态模式的使用者
提供方法供客户端触发状态转换或执行操作
自身不处理状态相关的逻辑,而是委托给当前状态对象
抽象状态(State):
定义所有具体状态的公共接口,声明环境类中可能触发的操作
可以是接口或抽象类,方法对应环境类在不同状态下的行为
具体状态(ConcreteState):
实现抽象状态接口,定义特定状态下的行为逻辑
在执行操作时可能触发状态转换(通过修改环境类的当前状态)
状态模式的核心是 "将状态封装为对象,通过状态对象的切换改变行为",将原本分散在环境类中的状态判断逻辑,拆分到不同的状态类中,使代码更清晰、易维护。
Java 实践示例
以 "订单状态流转" 为例实现状态模式:
订单存在多种状态:待支付、已支付、已发货、已完成、已取消
不同状态下允许的操作不同(如待支付状态可支付或取消,已支付状态可发货等)
通过状态模式封装每种状态的行为及状态转换逻辑
java
package com.example.demo;
public class StatePattern {
public static void main(String[] args) {
// 创建订单(环境类)
Order order = new Order();
System.out.println("=== 初始状态 ===");
order.getCurrentState();
// 尝试取消订单(待支付状态可取消)
System.out.println("\n=== 取消订单 ===");
order.cancel();
order.getCurrentState();
// 重新创建订单并完成全流程
order = new Order();
System.out.println("\n=== 新订单流程 ===");
order.pay(); // 支付
order.ship(); // 发货
order.complete(); // 完成
order.getCurrentState();
// 尝试在已完成状态执行发货(不允许)
System.out.println("\n=== 已完成状态执行发货 ===");
order.ship();
//=== 初始状态 ===
//当前订单状态:待支付
//
//=== 取消订单 ===
//订单已取消
//当前订单状态:已取消
//
//=== 新订单流程 ===
//订单支付成功
//订单已发货
//订单已完成
//当前订单状态:已完成
//
//=== 已完成状态执行发货 ===
//错误:订单已完成,无需发货
}
// 抽象状态:订单状态接口
public interface OrderState {
// 支付订单
void pay(Order order);
// 取消订单
void cancel(Order order);
// 发货
void ship(Order order);
// 完成订单
void complete(Order order);
// 获取状态名称
String getStateName();
}
// 具体状态:待支付
public static class PendingPaymentState implements OrderState {
@Override
public void pay(Order order) {
// 支付成功,转换为已支付状态
order.setState(new PaidState());
System.out.println("订单支付成功");
}
@Override
public void cancel(Order order) {
// 取消订单,转换为已取消状态
order.setState(new CancelledState());
System.out.println("订单已取消");
}
@Override
public void ship(Order order) {
System.out.println("错误:订单未支付,无法发货");
}
@Override
public void complete(Order order) {
System.out.println("错误:订单未支付,无法完成");
}
@Override
public String getStateName() {
return "待支付";
}
}
// 具体状态:已支付
public static class PaidState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("错误:订单已支付,无需重复支付");
}
@Override
public void cancel(Order order) {
order.setState(new CancelledState());
System.out.println("已支付订单取消成功(将安排退款)");
}
@Override
public void ship(Order order) {
order.setState(new ShippedState());
System.out.println("订单已发货");
}
@Override
public void complete(Order order) {
System.out.println("错误:订单未发货,无法完成");
}
@Override
public String getStateName() {
return "已支付";
}
}
// 具体状态:已发货(其他状态类类似实现)
public static class ShippedState implements OrderState {
@Override
public void pay(Order order) {
System.out.println("错误:订单已发货,无需支付");
}
@Override
public void cancel(Order order) {
System.out.println("错误:订单已发货,无法取消");
}
@Override
public void ship(Order order) {
System.out.println("错误:订单已发货,无需重复发货");
}
@Override
public void complete(Order order) {
order.setState(new CompletedState());
System.out.println("订单已完成");
}
@Override
public String getStateName() {
return "已发货";
}
}
// 具体状态:已完成
public static class CompletedState implements OrderState {
// 实现所有方法,已完成状态下大部分操作不允许
@Override
public void pay(Order order) {
System.out.println("错误:订单已完成,无需支付");
}
@Override
public void cancel(Order order) {
System.out.println("错误:订单已完成,无法取消");
}
@Override
public void ship(Order order) {
System.out.println("错误:订单已完成,无需发货");
}
@Override
public void complete(Order order) {
System.out.println("错误:订单已完成,无需重复操作");
}
@Override
public String getStateName() {
return "已完成";
}
}
// 具体状态:已取消
public static class CancelledState implements OrderState {
// 实现所有方法,已取消状态下大部分操作不允许
@Override
public void pay(Order order) {
System.out.println("错误:订单已取消,无法支付");
}
@Override
public void cancel(Order order) {
System.out.println("错误:订单已取消,无需重复取消");
}
@Override
public void ship(Order order) {
System.out.println("错误:订单已取消,无法发货");
}
@Override
public void complete(Order order) {
System.out.println("错误:订单已取消,无法完成");
}
@Override
public String getStateName() {
return "已取消";
}
}
// 环境类:订单
public static class Order {
// 持有当前状态的引用
private OrderState currentState;
// 初始化订单为待支付状态
public Order() {
this.currentState = new PendingPaymentState();
}
// 设置当前状态(供状态类调用以实现状态转换)
public void setState(OrderState state) {
this.currentState = state;
}
// 委托当前状态处理支付操作
public void pay() {
currentState.pay(this);
}
// 委托当前状态处理取消操作
public void cancel() {
currentState.cancel(this);
}
// 委托当前状态处理发货操作
public void ship() {
currentState.ship(this);
}
// 委托当前状态处理完成操作
public void complete() {
currentState.complete(this);
}
// 获取当前状态名称
public void getCurrentState() {
System.out.println("当前订单状态:" + currentState.getStateName());
}
}
}
状态模式的特点
- 优点:
消除大量条件判断:将状态相关的逻辑分散到不同状态类,替代冗长的if-else或switch-case
状态转换清晰:每个状态类负责自身的状态转换逻辑,职责单一
易于扩展:新增状态只需添加新的状态类,符合开闭原则
状态封装性好:状态的细节被隐藏在具体状态类中,环境类无需了解 - 缺点:
类数量增加:每个状态对应一个类,状态较多时会导致类数量膨胀
状态转换依赖环境类:状态类需要持有环境类引用才能实现状态转换,增加了耦合
与策略模式的区别:
状态模式:状态的切换由对象内部状态决定,策略通常由客户端主动设置
策略模式:关注不同算法的替换,状态模式关注状态变化导致的行为变化
状态模式的应用场景
- 状态流转明确的业务对象:
订单状态、流程状态、审批状态等有明确流转规则的对象
例如:电商订单(待支付→已支付→已发货→已完成)、请假审批流程 - 有限状态机(FSM):
具有有限个状态且状态间转换规则明确的系统
例如:电梯控制(开门→关门→运行→停止)、交通信号灯(红→黄→绿) - 游戏开发:
游戏角色状态( idle→行走→攻击→受伤→死亡)
游戏场景状态(加载中→正常→暂停→结束) - UI 组件状态:
按钮状态(可用→禁用→选中→未选中)
表单输入状态(未编辑→编辑中→验证通过→验证失败)
状态模式特别适合对象行为随状态变化而变化,且状态数量较多、转换逻辑复杂的场景。它通过将状态逻辑封装为独立对象,使系统更易于维护和扩展,是处理状态流转的最佳实践之一。