1. 什么是状态模式 ?
状态模式 (State Pattern):
- 类的行为是基于它的状态改变的。
- 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
2. 为什么使用状态模式?
解决代码中包含大量与对象状态有关的条件语句。
3. 应用场景
- 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
- 操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
- 这个状态通常用一个或多个枚举常量表示。
- 通常,有多个操作包含这一相同的条件结构。
- State 模式将每一个条件分支放入一个独立的类中。
- 这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
4. 原理
如下图结构所示:
状态模式包含以下主要角色。
1.环境(Context)角色:
也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
2.抽象状态(State)角色:
定义一个接口,用以封装环境对象中的特定状态所对应的行为。
3. 具体状态(Concrete State)角色:
实现抽象状态所对应的行为。
5. 状态模式-案例 1: 重构代码
重构前: 多条件 IF 下代码, 响应不同状态, 如下:
java
public String orderState(String state) {
if (state.equals("0")) {
return "已经发货";
}
if (state.equals("1")) {
return "正在运送中...调用第三方快递接口 展示 运送信息";
}
if (state.equals("2")) {
return "正在派送中... 返回派送人员信息";
}
if (state.equals("3")) {
return "已经签收,提示给用户快递员评价";
}
if (state.equals("4")) {
return "拒绝签收, 重新开始申请退单";
}
if (state.equals("5")) {
return "订单交易失败,调用短信接口提示 ";
}
return "未找到对应的状态";
}
}
重构后: 使用状态模式
1.环境(Context)角色:
java
package com.order.context;
import com.order.service.OrderStateService;
/**
* description: Context 也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
* date: 2020/9/21 13:44
* author: Calvin
* version: 1.0
*/
public class Context {
/**
* 订单状态
*/
private OrderStateService orderState;
/**
* 构造函数
* @param orderState 订单状态
*/
public Context(OrderStateService orderState) {
this.orderState = orderState;
}
/**
* 返回客户选择的状态
*/
public String switchOrderState() {
return orderState.state();
}
}
2.抽象状态(State)角色:
java
package com.order.service;
/**
* description: 订单状态: 定义一个接口,用以封装环境对象中的特定状态所对应的行为。
* date: 2020/9/21 13:35
* author: Calvin
* version: 1.0
*/
public interface OrderStateService {
/**
* 订单状态
* @return 订单状态内容
*/
String state();
}
3. 具体状态(Concrete State)角色:
- 实现抽象状态所对应的行为。
java
package com.order.service.impl;
import com.order.service.OrderStateService;
import org.springframework.stereotype.Service;
/**
* description: 订单状态-运送中-具体实现
* date: 2020/9/21 13:37
* author: Calvin
* version: 1.0
*/
@Service
public class InTransitOrderStateServiceImpl implements OrderStateService {
@Override
public String state() {
return " >>>订单状态->运送中,请耐心等待...>>>";
}
}
java
package com.order.service.impl;
import com.order.service.OrderStateService;
import org.springframework.stereotype.Service;
/**
* description: 订单状态-已发货-具体实现
* date: 2020/9/21 13:37
* author: Calvin
* version: 1.0
*/
@Service
public class ShippedOrderStateImpl implements OrderStateService {
@Override
public String state() {
return " >>>订单状态->已发货,请耐心等待...>>>";
}
}
java
package com.order.service.impl;
import com.order.service.OrderStateService;
import org.springframework.stereotype.Service;
/**
* description: 订单状态-已签收-具体实现
* date: 2020/9/21 13:37
* author: Calvin
* version: 1.0
*/
@Service
public class SignedOrderStateServiceImpl implements OrderStateService {
@Override
public String state() {
return ">>>订单状态->已经签收>>>";
}
}
4. 编写测试
java
package com.order.controller;
import com.order.context.Context;
import com.order.enumeration.OrderStateEnum;
import com.order.service.OrderStateService;
import com.order.utils.ContextUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* description: OrderStateController
* date: 2020/9/21 13:55
* author: Calvin
* version: 1.0
*/
@RestController
@RequestMapping("order")
public class OrderStateController {
@GetMapping(value = "state")
public String state(@RequestParam OrderStateEnum orderState) {
String className = orderState.getBeanName();
OrderStateService orderStateService = (OrderStateService) ContextUtils.getBean(className);
Context contextState = new Context(orderStateService);
return contextState.switchOrderState();
}
}
6. 结果演示

7. 状态模式与策略模式区别
状态模式:
观状态模式,各个状态的同一方法做的是不同的事,不能互相替换。
策略模式:
例如聚合支付平台,有支付宝、微信支付、银联支付,虽然策略不同,但最终做的事情都是支付,也就是说他们之间是可替换的。