设计模式之 状态模式

一、定义

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

二、分析

状态模式把不同的状态封装成类,并将对应的动作委托到对应的类中,只要状态一改变,对应的动作与会随之改变。

状态模式主要应用于业务逻辑中包含大量的状态判断的条件语句。我们可以把各个状态抽象出来,然后实现和各个状态相关的业务操作。

状态模式的优点在于:

  1. 封装了转换的规则:改变状态的方法放在具体状态类中切换;
  2. 把状态和状态有关的行为放在一个类中,便于添加新的状态;只需要编写新的状态,然后切换到这个状态即可。

三、类图

下面是状态模式的类图:

状态模式

四、代码实现

我们使用代码来实现状态模式:

源码:gitee

项目结构如下:

image-20210201173012235

1.抽象状态类 OrderState.java

package state;

/**
 * 订单状态抽象
 *
 * @author lixin
 */
public interface OrderState {

    /**
     * 查询订单的详细信息
     *
     * @param context 订单查询类
     * @param orderId 订单ID
     * @return 订单详情实体
     */
    OrderDetail findOrderDetail(OrderDetailContext context, Long orderId);

}

2.创建数据实体 OrderDetail.java

package state;

/**
 * 订单详情实体
 *
 * @author lixin
 */
public class OrderDetail {
    private Long id;
    private String name;
    private String orderNo;
    private Integer status;

    public OrderDetail(Long id, String name, String orderNo, Integer status) {
        this.id = id;
        this.name = name;
        this.orderNo = orderNo;
        this.status = status;
    }

    @Override
    public String toString() {
        return "OrderDetail{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", orderNo='" + orderNo + '\'' +
                ", status=" + status +
                '}';
    }

    public String getOrderNo() {
        return orderNo;
    }

    public void setOrderNo(String orderNo) {
        this.orderNo = orderNo;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

}

3.实现具体状态的操作逻辑 PayIngState.java PayCompleteState.java OrderExpireState.java

// PayIngState.java
package state.impl;

import state.OrderDetail;
import state.OrderDetailContext;
import state.OrderState;

/**
 * 订单支付中
 *
 * @author lixin
 */
public class PayIngState implements OrderState {

    @Override
    public OrderDetail findOrderDetail(OrderDetailContext context, Long orderId) {
        context.setOrderState(this);
        System.out.println("订单支付中...");
        OrderDetail orderDetail = findBiId(orderId);
        updateOrderState(orderDetail.getOrderNo());
        return findBiId(orderId);
    }

    /**
     * 到微信上查询订单是否交易完成
     * 如果完成就更新一下订单得到的状态
     *
     * @param orderNo 订单号
     */
    private void updateOrderState(String orderNo) {
        System.out.println("根据订单号到微信支付同步订单状态...");
    }

    /**
     * 根据订单ID查询订单信息
     *
     * @param orderId 订单ID
     * @return 订单信息
     */
    private OrderDetail findBiId(Long orderId) {
        System.out.println(String.format("根据orderId=%d查询到订单信息...", orderId));
        return new OrderDetail(1L, "手续费", "ZM2021021016560458", 0);
    }

}

// PayCompleteState.java 
package state.impl;

import state.OrderDetail;
import state.OrderDetailContext;
import state.OrderState;

/**
 * 订单支付完成
 *
 * @author lixin
 */
public class PayCompleteState implements OrderState {

    @Override
    public OrderDetail findOrderDetail(OrderDetailContext context, Long orderId) {
        context.setOrderState(this);
        System.out.println("订单支付完成...");
        return findBiId(orderId);
    }

    /**
     * 根据订单ID查询订单信息
     *
     * @param orderId 订单ID
     * @return 订单信息
     */
    private OrderDetail findBiId(Long orderId) {
        System.out.println(String.format("根据orderId=%d到完成的订单表中查询记录的信息...", orderId));
        return new OrderDetail(2L, "套餐3费用", "ZM2021021016562514", 1);
    }
}


// OrderExpireState.java
package state.impl;

import state.OrderDetail;
import state.OrderDetailContext;
import state.OrderState;

/**
 * 订单过期
 *
 * @author lixin
 */
public class OrderExpireState implements OrderState {

    @Override
    public OrderDetail findOrderDetail(OrderDetailContext context, Long orderId) {
        context.setOrderState(this);
        System.out.println("订单过期...");
        return findBiId(orderId);
    }

    /**
     * 根据订单ID查询订单信息
     *
     * @param orderId 订单ID
     * @return 订单信息
     */
    private OrderDetail findBiId(Long orderId) {
        System.out.println(String.format("根据orderId=%d到过期订单表中查询信息...", orderId));
        return new OrderDetail(3L, "套餐99费用", "ZM2021021016560345", -1);
    }
}

4.创建使用状态的类 OrderDetailContext.java

package state;

/**
 * 订单操作类
 *
 * @author lixin
 */
public class OrderDetailContext {
    private OrderState orderState;

    public OrderDetailContext() {
    }

    public OrderState getOrderState() {
        return orderState;
    }

    public void setOrderState(OrderState orderState) {
        this.orderState = orderState;
    }

    /**
     * 查询订单详情
     *
     * @param orderId 订单ID
     * @return 订单详情
     */
    public OrderDetail findOrderDetail(Long orderId) {
        return orderState.findOrderDetail(this, orderId);
    }
}

5.创建测试类

package state;

import state.impl.OrderExpireState;
import state.impl.PayCompleteState;
import state.impl.PayIngState;

/**
 * 状态模式测试类
 *
 * @author lixin
 */
public class StateDemoMain {

    public static void main(String[] args) {
        // 创建Context使用状态
        OrderDetailContext context = new OrderDetailContext();

        // 改变状态
        context.setOrderState(new PayIngState());
        // 执行对应状态的处理方法
        OrderDetail detail1 = context.findOrderDetail(1L);
        System.out.println(detail1);

        System.out.println("==================");
        // 切换到另外一个状态
        context.setOrderState(new PayCompleteState());
        // 执行对应状态的处理方法
        OrderDetail detail2 = context.findOrderDetail(2L);
        System.out.println(detail2);

        System.out.println("==================");
        // 切换到另外一个状态
        context.setOrderState(new OrderExpireState());
        // 执行对应状态的处理方法
        OrderDetail detail3 = context.findOrderDetail(3L);
        System.out.println(detail3);
    }

}

/* 输出结果:

订单支付中...
根据orderId=1查询到订单信息...
根据订单号到微信支付同步订单状态...
根据orderId=1查询到订单信息...
OrderDetail{id=1, name='手续费', orderNo='ZM2021021016560458', status=0}
==================
订单支付完成...
根据orderId=2到完成的订单表中查询记录的信息...
OrderDetail{id=2, name='套餐3费用', orderNo='ZM2021021016562514', status=1}
==================
订单过期...
根据orderId=3到过期订单表中查询信息...
OrderDetail{id=3, name='套餐99费用', orderNo='ZM2021021016560345', status=-1}

*/
posted @ 2021-02-01 17:18  喵喵扑  阅读(204)  评论(0编辑  收藏  举报