一 本质
状态模式本质上是一种基于状态和事件的状态机,比如下面的订单流程的状态图
通过状态图,设计如下关系表来比较
- Context 类为环境角色, 用于维护State实例,这个实例定义当前状态
- State 是抽象状态角色,定义一个接口封装与Context 的一个特点接口相关行为
- ConcreteState 具体的状态角色,每个子类实现一个与Context 的一个状态相关行为
二 案例
状态模式在实际项目-借贷平台 源码剖析:
- 借贷平台的订单,有审核-发布-抢单 等等 步骤,随着操作的不同,会改变订单的
状态, 项目中的这个模块实现就会使用到状态模式 - 通常通过if/else判断订单的状态,从而实现不同的逻辑,伪代码如下
if(审核){
//审核逻辑
}elseif(发布){
//发布逻辑
}elseif(接单){
//接单逻辑
}
问题分析 :
这类代码难以应对变化,在添加一种状态时,我们需要手动添加if/else,在添加一种功能时,要对所有的状态进行判断。因此代码会变得越来越臃肿,并且一旦没有处理某个状态,便会发生极其严重的BUG,难以维护
2.1StateEnum
package com.yqq.pattern.state.money;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/13:59
* @Description: 状态枚举类
*/
public enum StateEnum {
//订单生成(待审核)
GENERATE(1,"GENERATE"),
//已审核
REVIEWED(2,"REVIEWED"),
//已发布
PUBLISHED(3,"PUBLISHED"),
//待付款
NOT_PAY(4,"NOT_PAY"),
//已付款
PAID(5,"PAID"),
//已完结
FEED_BACKED(6,"FEED_BACKED");
private int key;
private String value;
StateEnum(int key,String value){
this.key = key;
this.value = value;
}
public int getKey(){
return key;
}
public String getValue(){
return value;
}
}
2.2State
package com.yqq.pattern.state.money;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:08
* @Description: 状态接口
*/
public interface State {
/**
* 电审
*/
void checkEvent(Context context);
/**
* 电审失败
*/
void checkFailEvent(Context context);
/**
* 定价发布
*/
void makePriceEvent(Context context);
/**
* 接单
*/
void acceptOrderEvent(Context context);
/**
* 无人接单失效
*/
void notPeopleAcceptEvent(Context context);
/**
* 付款
*/
void payOrderEvent(Context context);
/**
* 接单有人支付失效
*/
void orderFailureEvent(Context context);
/**
* 反馈
*/
void feedBackEvent(Context context);
/**
* 获取当前状态
*/
String getCurrentState();
}
2.3AbstractState
package com.yqq.pattern.state.money;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:17
* @Description: 抽象类,默认实现了 State 接口的所有方法,该类的所有方法,其子类(具体的状态类),
* 可以有选择的进行重写
*/
public abstract class AbstractState implements State{
protected static final RuntimeException EXCEPTION = new RuntimeException("操作不允许");
@Override
public void checkEvent(Context context) {
throw EXCEPTION;
}
@Override
public void checkFailEvent(Context context) {
throw EXCEPTION;
}
@Override
public void makePriceEvent(Context context) {
throw EXCEPTION;
}
@Override
public void acceptOrderEvent(Context context) {
throw EXCEPTION;
}
@Override
public void notPeopleAcceptEvent(Context context) {
throw EXCEPTION;
}
@Override
public void payOrderEvent(Context context) {
throw EXCEPTION;
}
@Override
public void orderFailureEvent(Context context) {
throw EXCEPTION;
}
@Override
public void feedBackEvent(Context context) {
throw EXCEPTION;
}
}
2.4Context
package com.yqq.pattern.state.money;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:20
* @Description: 环境上下文
*/
public class Context extends AbstractState{
//当前的状态 state, 根据我们的业务流程处理,不停的变化
private State state;
@Override
public void checkEvent(Context context) {
state.checkEvent(this);
getCurrentState();
}
@Override
public void checkFailEvent(Context context) {
state.checkFailEvent(this);
getCurrentState();
}
@Override
public void makePriceEvent(Context context) {
state.makePriceEvent(this);
getCurrentState();
}
@Override
public void acceptOrderEvent(Context context) {
state.acceptOrderEvent(this);
getCurrentState();
}
@Override
public void notPeopleAcceptEvent(Context context) {
state.notPeopleAcceptEvent(this);
getCurrentState();
}
@Override
public void payOrderEvent(Context context) {
state.payOrderEvent(this);
getCurrentState();
}
@Override
public void orderFailureEvent(Context context) {
state.orderFailureEvent(this);
getCurrentState();
}
@Override
public void feedBackEvent(Context context) {
state.feedBackEvent(this);
getCurrentState();
}
public State getState(){
return state;
}
public void setState(State state){
this.state = state;
}
@Override
public String getCurrentState() {
System.out.println("当前状态 : " + state.getCurrentState());
return state.getCurrentState();
}
}
2.5ReviewState
package com.yqq.pattern.state.money.impl;
import com.yqq.pattern.state.money.AbstractState;
import com.yqq.pattern.state.money.Context;
import com.yqq.pattern.state.money.StateEnum;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:50
* @Description: 已审核
*/
public class ReviewState extends AbstractState {
/**
* 已发布
*/
@Override
public void makePriceEvent(Context context) {
context.setState(new PublishState());
}
/**
* 获取当前状态
*/
@Override
public String getCurrentState() {
return StateEnum.REVIEWED.getValue();
}
}
2.6PublishState
package com.yqq.pattern.state.money.impl;
import com.yqq.pattern.state.money.AbstractState;
import com.yqq.pattern.state.money.Context;
import com.yqq.pattern.state.money.StateEnum;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:50
* @Description: 已发布
*/
public class PublishState extends AbstractState {
/**
* 未付款
*/
@Override
public void acceptOrderEvent(Context context) {
//把当前状态设置为 NotPayState。。。
//至于应该变成哪个状态,有流程图来决定
context.setState(new NotPayState());
}
/**
* 已完结
*/
@Override
public void notPeopleAcceptEvent(Context context) {
context.setState(new FeedBackState());
}
/**
* 获取当前状态
*/
@Override
public String getCurrentState() {
return StateEnum.PUBLISHED.getValue();
}
}
2.7PaidState
package com.yqq.pattern.state.money.impl;
import com.yqq.pattern.state.money.AbstractState;
import com.yqq.pattern.state.money.Context;
import com.yqq.pattern.state.money.StateEnum;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:50
* @Description: 已付款
*/
public class PaidState extends AbstractState {
/**
* 已完结
*/
@Override
public void feedBackEvent(Context context) {
context.setState(new FeedBackState());
}
/**
* 获取当前状态
*/
@Override
public String getCurrentState() {
return StateEnum.PAID.getValue();
}
}
2.8NotPayState
package com.yqq.pattern.state.money.impl;
import com.yqq.pattern.state.money.AbstractState;
import com.yqq.pattern.state.money.Context;
import com.yqq.pattern.state.money.StateEnum;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:49
* @Description: 待付款
*/
public class NotPayState extends AbstractState {
/**
* 已付款
*/
@Override
public void payOrderEvent(Context context) {
context.setState(new PaidState());
}
/**
* 已完结
*/
@Override
public void feedBackEvent(Context context) {
context.setState(new FeedBackState());
}
/**
* 获取当前状态
*/
@Override
public String getCurrentState() {
return StateEnum.NOT_PAY.getValue();
}
}
2.9GenerateState
package com.yqq.pattern.state.money.impl;
import com.yqq.pattern.state.money.AbstractState;
import com.yqq.pattern.state.money.Context;
import com.yqq.pattern.state.money.StateEnum;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:45
* @Description: 订单生成(待审核)
*/
public class GenerateState extends AbstractState {
/**
* 已审核
*/
@Override
public void checkEvent(Context context) {
context.setState(new ReviewState());
}
/**
* 已完结
*/
@Override
public void checkFailEvent(Context context) {
context.setState(new FeedBackState());
}
/**
* 获取当前状态
*/
@Override
public String getCurrentState() {
return StateEnum.GENERATE.getValue();
}
}
2.10FeedBackState
package com.yqq.pattern.state.money.impl;
import com.yqq.pattern.state.money.AbstractState;
import com.yqq.pattern.state.money.StateEnum;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/14:36
* @Description: 已完结
*/
public class FeedBackState extends AbstractState {
/**
* 获取当前状态
*/
@Override
public String getCurrentState() {
return StateEnum.FEED_BACKED.getValue();
}
}
2.11ClientTest (测试)
package com.yqq.pattern.state.money;
import com.yqq.pattern.state.money.impl.PublishState;
/**
* Created with IntelliJ IDEA.
*
* @Author: yqq
* @Date: 2022/08/20/15:16
* @Description:
*/
public class ClientTest {
public static void main(String[] args) {
//创建context 对象
Context context = new Context();
//将当前状态设置为 PublishState
context.setState(new PublishState());
System.out.println(context.getCurrentState());
// //publish --> not pay
context.acceptOrderEvent(context);
// //not pay --> paid
context.payOrderEvent(context);
}
}
三 状态模式的注意事项和细节
- 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
- 方便维护。将容易产生问题的if-else语句删除了,如果把每个状态的行为都放到一
个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多if-else语句,
而且容易出错 - 符合“开闭原则”。容易增删状态
- 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维
护难度 - 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状
态要求有不同的行为的时候,可以考虑使用状态模式