【大道模式】状态模式 - State Pattern(审核状态流转)

news2024/9/21 2:37:02

       最近在实现一个简单的审核系统,包含多个审核状态和多个审核动作,将业务逻辑映射到代码中感觉会有很多繁杂的逻辑,因此,会思考用一个比较通用、易扩展、易维护、易测试的模式来应对这种场景,了解了一下,就是状态模式。笔者将业务场景简单化,并通过状态模式来解决这个问题,业务场景如下:

几点说明:

1.用户提价资料后,为初始状态, 可以审核通过,也可以审核拒绝;

2.审核通过后状态不可以改变;

3.审核拒绝后可以重新发起审核;

        在正式介绍之前,可以思考一下,如何实现这种场景?如果状态比较多,流程复杂,如何解决?

一、核心概念

        状态机有三部分组成:

1)状态(State):整个业务流转过程中所有的状态,对于本例来说有三个状态:初始、审核通过、审核拒绝;

2)事件(Event):转移条件(Transition Condition),事件的触发会导致状态的转移以及相应的动作;

3)动作(Action):事件转移过程对对应的时间,包括发邮件,更新数据库,调用API等等,当然相关动作未必必须执行。

二、代码框架

public enum State{} //定义整体流程中的所有状态 

public enum Event{} //定义所有事件

public interface IAudit {} //定义事件执行接口类,每个method都是某个时间event对应的具体指定动作

public abstract class AbstractAudit implements IAudit {} //事件执行抽象类

public class StateAudit extends AbstractAudit implements IAudit {} //具体状态类,method为当前状态下对应event执行的具体事情。

public class AuditStateMachine {} //对外业务类

三、业务实现

State.java:

package design.pattern.statepattern.test;


public enum State {

    audit_init("audit_init"),
    audit_approved("audit_approved"),
    audit_rejected("audit_rejected");

    private String value;

    private State(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }
}

Event.java:

package design.pattern.statepattern.test;


public enum Event {
    APPROVE("approve"),
    REJECT("reject"),
    GOBACKINIT("gobackinit");

    private String event;

    private Event(String event) {
        this.event = event; }

    public String getEvent() {
        return this.event;
    }
}

IAudit.java:

public interface IAudit {

    void triggerEvent(Event e);

    String auditApproved();

    String auditReject();

    String goBackToReview();
}

AbstractAudit.java:

package design.pattern.statepattern.test;


public abstract class AbstractAudit implements IAudit {

    //todo: use a table mapping
    @Override
    public void triggerEvent(Event e) {
        if (e.getEvent() == Event.APPROVE.getEvent()) {
            auditApproved();
        } else if (e.getEvent() == Event.REJECT.getEvent()) {
            auditReject();
        } else if (e.getEvent() == Event.GOBACKINIT.getEvent()) {
            goBackToReview();
        } else {
            System.out.println("invalid event = " + e.getEvent());
        }
    }

    @Override
    public String auditApproved() {
        System.out.println("auditApproved-N/A");
        return "N/A";
    }

    @Override
    public String auditReject() {
        System.out.println("auditReject-N/A");
        return "N/A";
    }

    @Override
    public String goBackToReview() {
        System.out.println("goBackToReview-N/A");
        return "N/A";
    }
}

ApprovedAudit.java:

public class ApprovedAudit extends AbstractAudit implements IAudit {}

InitAudit.java:

package design.pattern.statepattern.test.impl;

import design.pattern.statepattern.test.AbstractAudit;
import design.pattern.statepattern.test.IAudit;
import design.pattern.statepattern.test.State;


public class InitAudit  extends AbstractAudit implements IAudit {

    @Override
    public String auditApproved() {
        System.out.println("this is InitAudit-auditApproved");
        return null;

    }

    @Override
    public String auditReject() {
        System.out.println("this is InitAudit-auditReject");
        return null;
    }

}

RejectedAudit:

package design.pattern.statepattern.test.impl;

import design.pattern.statepattern.test.AbstractAudit;
import design.pattern.statepattern.test.IAudit;
import design.pattern.statepattern.test.State;


public class RejectedAudit  extends AbstractAudit implements IAudit {

    @Override
    public String goBackToReview() {
        System.out.println("this is RejectedAudit-goBackToReview");
        return  null;
    }
}

AuditStateMachine.java:

package design.pattern.statepattern;

import design.pattern.statepattern.test.Event;
import design.pattern.statepattern.test.IAudit;
import design.pattern.statepattern.test.State;
import design.pattern.statepattern.test.impl.ApprovedAudit;
import design.pattern.statepattern.test.impl.InitAudit;
import design.pattern.statepattern.test.impl.RejectedAudit;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AuditStateMachine {

    protected static Map<State, IAudit> statusMap = new ConcurrentHashMap<>();

    static {
        statusMap.put(State.audit_init, new InitAudit());
        statusMap.put(State.audit_approved, new ApprovedAudit());
        statusMap.put(State.audit_rejected, new RejectedAudit());
    }

    public void function(String recordId, Event event) {
        State currentState = getStateByRecordIdFromDb(recordId);

        function(currentState, event);
    }

    public void function(State currentState, Event event) {
        //1. get state class by currentState
        IAudit statusAudit = statusMap.get(currentState);
        if (null == statusAudit) {
            System.out.println("invalid state = " + currentState.getValue());
            return;
        }

        //2. execute event by event type
        statusAudit.triggerEvent(event);
    }

}

Author:忆之独秀

Email:leaguenew@qq.com

注明出处:https://blog.csdn.net/lavorange/article/details/128170927

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/61881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java数据结构与Java算法学习Day03---线性表(简略笔记记录)

目录 一、线性表 38 二、顺序表 39 三、链表 45 3.1单向链表 46、47、48 3.2双向链表 49 3.3链表反转 &#xff08;面试中高频题目&#xff09; 56 3.4快慢指针 57 3.4.1中间值问题 57 3.4.2单向链表是否有环问题 58 3.4.3有环链表入口问题 60 3.5循环链表 61 3.6…

(Java)Mybatis学习笔记(三)

前言 继续学习MyBatis各种查询功能章节&#xff0c;争取早日学完mybatis MyBatis中各种查询功能 ❄️若查询出的 数据只有一条&#xff0c;可以通过实体类对象或集合接收 ❄️若查询出的 数据有多条&#xff0c;可以通过集合接收&#xff0c;一定不能通过实体类对象接收&am…

社区系统项目复盘-8

文章目录任务执行和调度热帖排行生成长图优化网站的性能使用Quartz执行定时任务&#xff0c;实现热帖排行功能时&#xff0c;通过定时任务定时计算帖子分数&#xff0c;降低计算的数据量。使用wkhtmltopdf生成长图。通过多级缓存对热帖功能进行优化&#xff0c;提升网站性能。 …

回归分析-书后习题回顾总结

4-1 题目 理论基础 经典多元线性回归模型 参数β\betaβ的最小二乘估计 设rank(C)m1≤nrank(C)m1≤nrank(C)m1≤n&#xff0c;则β^b(CTC)−1CTY\widehat{\beta}b(C^{T}C)^{-1}C^{T}Yβ​b(CTC)−1CTY是β\betaβ的最小二乘估计 具体解题

[附源码]计算机毕业设计网文论坛管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

本田125摩托安装版成型模具设计及仿真(任务书+说明书+工艺卡片+cad图纸+sw三维图)

目录 1 绪论 1 2 模塑工艺规程的编制 3 2.1塑件的工艺性分析 3 2.1.1塑件的原材料分析 3 2.2塑件的结构和尺寸精度及表面质量分析 4 2.2.1结构分析 4 2.2.2尺寸精度分析 4 2.2.3表面质量分析 4 2&#xff0e;3计算塑件的体积和质量 4 2&#xff0e;4塑件成型工艺参数的确定 5 2…

34. 在排序数组中查找元素的第一个和最后一个位置

&#x1f308;&#x1f308;&#x1f604;&#x1f604; 欢迎来到茶色岛独家岛屿&#xff0c;本期将为大家揭晓34. 在排序数组中查找元素的第一个和最后一个位置&#xff0c;做好准备了么&#xff0c;那么开始吧。 &#x1f332;&#x1f332;&#x1f434;&#x1f434; 一、题…

[激光原理与应用-36]:《光电检测技术-3》- 光学测量基础 - 光电效应与光电探测器的基本原理

目录 一、概述 二、光电检测的理论基础&#xff1a;光电效应 三、分类 3.1 光子效应 3.2 热效应 四、光电检测器的参数 五、常见的光电探测器 5.1 光电倍增管&#xff1a;微弱光信号转换成电信号 5.2 光电导器件&#xff1a;电阻或电流随着光强的变化而变化 5.3 光伏…

idea 启动报错 Command line is too long

idea 运行启动类报错 Command line is too long 启动报错信息&#xff1a;Error running ‘Application‘: Command line is too long. 翻译过来就是&#xff1a;启动命令过长&#xff01; 解决方案 1、点开项目启动配置项目&#xff1b; 2、shorten command line 选项选择 J…

(五)进程管理:进程的状态与控制

文章目录一、进程的状态二、进程控制1. 进程控制的原语2. 挂起与激活一、进程的状态 进程的生命周期&#xff1a;从创建到终止的过程 进程的三种基本状态 就绪&#xff08;Ready&#xff09; 可运行而未运行的状态&#xff0c;进程已经分配到除了处理机外的所有资源&#xf…

[附源码]计算机毕业设计校园订餐系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

python数据分析及可视化(十六)金融量化(金融工具、金融分析、Tushare安装使用、双均线分析)

金融介绍 金融就是对现有资源进行重新整合之后&#xff0c;实现价值和利润的等效流通。 比如小明想把手里的资金投资给小李&#xff0c;而小李有好的增值项目但是缺少资金&#xff0c;如果小李的项目创业成功&#xff0c;小明的资金就会增长。 金融工具 在金融市场中可交易的…

时序数据库基本概念学习

目录1、时序数据1.1 定义1.2 数学模型1.3 数据特点2、存储优化3、存储原理4、时序数据模型4.1 基于标签&#xff08;tag-value&#xff09;4.2 基于树形&#xff08;tree schema&#xff09;1、时序数据 1.1 定义 时序数据就是一串按时间维度索引的数据&#xff0c;这类数据描…

C++11闭包函数的几种实现方法

什么是闭包函数 函数就是对传入的一组参数进行运算的行为&#xff0c;闭包函数就是有状态的函数&#xff0c;在参与运算时&#xff0c;除了传入的参数外&#xff0c;还可以对上下文的状态进行运算。类函数运行时就是典型的闭包函数&#xff0c;类函数运行起来后其对象就是状态…

Spring - @PostConstruct 源码解析

文章目录Prejavax.annotation.PostConstruct 注解源码解析扩展示例Pre Spring Boot - 扩展接口一览 javax.annotation.PostConstruct 注解 Documented Retention (RUNTIME) Target(METHOD) public interface PostConstruct { }严格意义上来说这个并不算一个扩展点&#xff0c…

[附源码]计算机毕业设计校园订餐管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

文献阅读总结(4)Graph convolution machine for context-aware recommender system

上下文感知的图卷积推荐系统 推荐方面的最新进展表明&#xff0c;可以通过在用户-项目交互图上执行图卷积来学习更好的用户和项目表示&#xff0c;然而&#xff0c;该方法在协同过滤(CF)的场景中有一定的局限性&#xff0c;在这种场景中交互上下文是不可用的。 在这项工作中&…

python关联规则学习:FP-Growth算法对药品进行“菜篮子”分析

产品可以根据销售者进行分类 在Evolution上&#xff0c;有一些顶级类别&#xff08;“药品”&#xff0c;“数字商品”&#xff0c;“欺诈相关”等&#xff09;细分为特定于产品的页面。每个页面包含不同供应商的几个列表。 最近我们被客户要求撰写关于关联规则的研究报告&am…

字符串的扩展

字符串解读 es6加强了对Unicode 的支持&#xff0c;允许\uxxxx的形式展现一个字符&#xff0c;例如&#xff1a; console.log(\u0061); // 打印 a\u后面的为字符的 Unicode 码点 \u 后面4位 xxxx 但是这种写法只识别 \u0000 到 \UFFFF 之间的字符&#xff0c;超出需要使用两…

第十七章 管理组件库的pull request

一个好的项目很少会由一个人来独立完成。即使你完成了所有功能实现&#xff0c;也需要有人给你 Review 和提建议、找 Bug。比如添加新的组件、完善文档、添加单元测试、提出改进意见。 这节课我们就介绍一下如何参与开源社区的代码贡献。对于任何一个开源项目&#xff0c;我们…