Skip to content

1. 什么是状态模式 ?

状态模式 (State Pattern):

  • 类的行为是基于它的状态改变的。
  • 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

2. 为什么使用状态模式?

解决代码中包含大量与对象状态有关的条件语句。

3. 应用场景

  1. 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  2. 操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
  • 这个状态通常用一个或多个枚举常量表示。
  • 通常,有多个操作包含这一相同的条件结构。
  • 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. 结果演示

代码链接:https://github.com/1016280226/design-patterns

7. 状态模式与策略模式区别

状态模式:

  • 重点在各状态之间的切换从而做不同的事情

  • 状态模式不同状态下做的事情不同

  • 状态模式封装了对象的状态, 状态是跟对象密切相关的,它不能被重用.

观状态模式,各个状态的同一方法做的是不同的事,不能互相替换。

策略模式:

  • 更侧重于根据具体情况选择策略,并不涉及切换

  • 而策略模式做的都是同一件事

  • 略模式封装算法或策略, 而通过从 Context 中分离出策略或算法,我们可以重用它们

例如聚合支付平台,有支付宝、微信支付、银联支付,虽然策略不同,但最终做的事情都是支付,也就是说他们之间是可替换的。