0
点赞
收藏
分享

微信扫一扫

【设计模式】-状态模式->借贷平台(源码与类图解析)


一 本质

状态模式本质上是一种基于状态和事件的状态机,比如下面的订单流程的状态图

【设计模式】-状态模式->借贷平台(源码与类图解析)_设计模式


通过状态图,设计如下关系表来比较

【设计模式】-状态模式->借贷平台(源码与类图解析)_设计模式_02

【设计模式】-状态模式->借贷平台(源码与类图解析)_ide_03

  1. Context 类为环境角色, 用于维护State实例,这个实例定义当前状态
  2. State 是抽象状态角色,定义一个接口封装与Context 的一个特点接口相关行为
  3. ConcreteState 具体的状态角色,每个子类实现一个与Context 的一个状态相关行为

二 案例

状态模式在实际项目-借贷平台 源码剖析:

  1. 借贷平台的订单,有审核-发布-抢单 等等 步骤,随着操作的不同,会改变订单的
    状态, 项目中的这个模块实现就会使用到状态模式
  2. 通常通过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);
}
}

【设计模式】-状态模式->借贷平台(源码与类图解析)_封装_04

三 状态模式的注意事项和细节

  1. 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中
  2. 方便维护。将容易产生问题的if-else语句删除了,如果把每个状态的行为都放到一
    个类中,每次调用方法时都要判断当前是什么状态,不但会产出很多if-else语句,
    而且容易出错
  3. 符合“开闭原则”。容易增删状态
  4. 会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维
    护难度
  5. 应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状
    态要求有不同的行为的时候,可以考虑使用状态模式


举报

相关推荐

0 条评论