设计模式学习(十二)状态模式
目录
- 一、定义
- 1.1 什么是状态模式?
- 1.2 状态模式的优缺点
- 1.3 状态模式的实现结构
- 二、适用场景
- 三、代码示例:订单状态管理
- 3.1 背景介绍
- 3.2 问题分析
- 3.3 状态模式解决方案
- 1)定义状态接口
- 2)实现具体状态类
- 3)定义环境类
- 4)客户端测试
- 4)测试结果
一、定义
1.1 什么是状态模式?
状态模式(State Pattern) 是一种 行为型 设计模式,对有状态的对象,把复杂的 “判断逻辑” 提取到不同的状态对象中,允许状态对象在其内部状态发生改变时,改变其行为。
1.2 状态模式的优缺点
状态模式的优点:
- 结构清晰 :状态模式将与特定状态相关的行为局部化道一个状态中,并且将不同状态的行为分割开来,满足 “但一职责原则”。
- 将状态转换显示化:减少对象间的相互依赖,将不同的状态引入独立的对象中会是的状态转换变得更加明确,且减少对相见的相互依赖。
- 状态类职责明确:有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
状态模式的缺点:
- 状态模式的使用必然会增加系统的类与对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
- 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。
1.3 状态模式的实现结构
状态模式把受环境改变的对象行为包装在不同的状态对象里,其意图是让一个对象在其内部状态改变的时候,其行为也随之改变。现在我们来分析其基本结构和实现方法。
状态模式主要包含三个角色:
- Context(环境类):定义客户端感兴趣的接口,维护一个 State 子类的实例,这个示例定义当前状态。
- State(抽象状态类):定义一个接口,用以封装 Context 的特定状态相关的行为。
- ConcreteState(具体状态类):每一个子类实现一个与 Context 的一个状态相关的行为。
二、适用场景
适用场景一:算法框架固定的场景
- 适用原因:当多个相关类需要执行相同的工作流程或算法骨架,但其中某些具体步骤的实现各不相同。这些类共享一个通用的操作序列,只是在特定环节存在差异化实现。
- 状态模式解决的问题:消除重复的过程控制代码,确保所有子类都遵循相同的执行顺序和流程规范。避免了在每个具体类中重复编写相同的流程控制逻辑,同时也防止了因流程修改需要在多个地方同步更新的维护负担。
适用场景二:代码复用的场景
- 适用原因:系统中存在多个类包含大量相同的行为代码,只有部分核心逻辑存在差异。这些类在整体功能上高度相似,但在关键步骤上需要个性化实现。
- 状态模式解决的问题:通过将公共代码提升到父类中,显著减少代码重复。当公公逻辑需要修改时,只需在父类中修改一处即可影响所有子类,大大提高了代码的可维护性和一致性。
适用场景三:控制子类扩展的场景
- 适用原因:需要确保子类在扩展时不会破坏核心算法的结构,或者需要限制子类只能重写特定的操作步骤。系统要求对扩展行为进行规范化管理。
- 解决的问题:防止子类随意修改关键流程,确保系统的稳定性和一致性。通过模板方法定义不可更改的算法骨架,既保证了扩展的灵活性,又维护了核心流程的稳定性。
三、代码示例:订单状态管理
3.1 背景介绍
在电商系统下,订单状态管理是一个典型的状态模式应用场景。订单会经历从创建到完成的多个状态,每个状态下可执行的操作各不相同。
3.2 问题分析
如果不使用状态模式,我们可能会写出这样的代码:
public class Order {private String state;public void handle() {if ("pending".equals(state)) {System.out.println("订单待支付,可以支付或取消");} else if ("paid".equals(state)) {System.out.println("订单已支付,可以发货");} else if ("shipped".equals(state)) {System.out.println("订单已发货,等待确认收货");} else if ("completed".equals(state)) {System.out.println("订单已取消,不能进行任何操作");}}public void pay() {if ("pending".equals(state)) {state = "paid";System.out.println("支付成功");} else {System.out.println("当前状态不能支付");}}
}
这种方式的缺点很明显:
- 大量的
if-else语句,代码臃肿; - 违反开闭原则,新增状态需要修改原有代码;
- 状态转换逻辑分散在各个方法中,难以维护;
3.3 状态模式解决方案
代码 UML 如下:
1)定义状态接口
/*** 订单状态接口*/
public interface OrderState {void handle(OrderContext context);void pay(OrderContext context);void ship(OrderContext context);void confirm(OrderContext context);void cancel(OrderContext context);
}
2)实现具体状态类
/*** 待支付状态*/
public class PendingState implements OrderState {@Overridepublic void handle(OrderContext context) {System.out.println("订单待支付,可以支付或取消");}@Overridepublic void pay(OrderContext context) {System.out.println("支付成功,订单状态变为已支付");context.setState(new PaidState());}@Overridepublic void ship(OrderContext context) {System.out.println("待支付状态不能发货");}@Overridepublic void confirm(OrderContext context) {System.out.println("待支付状态不能确认收货");}@Overridepublic void cancel(OrderContext context) {System.out.println("订单已取消");context.setState(new CancelledState());}
}/*** 已支付状态*/
public class PaidState implements OrderState {@Overridepublic void handle(OrderContext context) {System.out.println("订单已支付,可以发货或取消");}@Overridepublic void pay(OrderContext context) {System.out.println("订单已支付,无需重复支付");}@Overridepublic void ship(OrderContext context) {System.out.println("发货成功,订单状态变为已发货");context.setState(new ShippedState());}@Overridepublic void confirm(OrderContext context) {System.out.println("已支付状态不能确认收货");}@Overridepublic void cancel(OrderContext context) {System.out.println("取消订单,退款处理中");context.setState(new CancelledState());}
}/*** 已发货状态*/
public class ShippedState implements OrderState {@Overridepublic void handle(OrderContext context) {System.out.println("订单已发货,等待确认收货");}@Overridepublic void pay(OrderContext context) {System.out.println("已发货状态不能支付");}@Overridepublic void ship(OrderContext context) {System.out.println("订单已发货,不能重复发货");}@Overridepublic void confirm(OrderContext context) {System.out.println("确认收货,订单完成");context.setState(new CompletedState());}@Overridepublic void cancel(OrderContext context) {System.out.println("已发货状态不能取消,请联系客服");}
}/*** 已完成状态*/
public class CompletedState implements OrderState {@Overridepublic void handle(OrderContext context) {System.out.println("订单已完成,可以评价");}@Overridepublic void pay(OrderContext context) {System.out.println("订单已完成,不能支付");}@Overridepublic void ship(OrderContext context) {System.out.println("订单已完成,不能发货");}@Overridepublic void confirm(OrderContext context) {System.out.println("订单已完成,不能重复确认");}@Overridepublic void cancel(OrderContext context) {System.out.println("订单已完成,不能取消");}
}/*** 已取消状态*/
public class CancelledState implements OrderState {@Overridepublic void handle(OrderContext context) {System.out.println("订单已取消,不能进行任何操作");}@Overridepublic void pay(OrderContext context) {System.out.println("订单已取消,不能支付");}@Overridepublic void ship(OrderContext context) {System.out.println("订单已取消,不能发货");}@Overridepublic void confirm(OrderContext context) {System.out.println("订单已取消,不能确认收货");}@Overridepublic void cancel(OrderContext context) {System.out.println("订单已取消,不能重复取消");}
}
3)定义环境类
/*** 订单上下文类*/
public class OrderContext {private OrderState state;private String orderId;public OrderContext(String orderId) {this.orderId = orderId;// 初始状态为待支付this.state = new PendingState();}public void setState(OrderState state) {this.state = state;}public OrderState getState() {return state;}// 委托给状态对象处理public void handle() {state.handle(this);}public void pay() {state.pay(this);}public void ship() {state.ship(this);}public void confirm() {state.confirm(this);}public void cancel() {state.cancel(this);}public String getOrderId() {return orderId;}
}
4)客户端测试
/*** 测试类*/
public class StatePatternDemo {public static void main(String[] args) {OrderContext order = new OrderContext("ORDER001");// 初始状态order.handle();order.pay();// 已支付状态order.handle();order.ship();// 已发货状态order.handle();order.confirm();// 已完成状态order.handle();order.cancel();System.out.println("====================================");// 测试异常流程OrderContext order2 = new OrderContext("ORDER002");order2.ship(); // 待支付状态尝试发货order2.cancel(); // 取消订单order2.pay(); // 已取消状态尝试支付}
}
4)测试结果
执行 main() 之后,结果如下所示:
整理完毕,完结撒花~🌻
参考地址:
1.状态模式(State模式),https://blog.csdn.net/qq_35784669/article/details/121238278
