当前位置: 首页 > news >正文

设计模式(实战项目)-状态模式

需求背景:存在状态流转的预约单

一.数据库设计

CREATE TABLE `appointment` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',`appoint_type` int(11) NOT NULL COMMENT '预约类型(0:线下查房...)',`appoint_user_id` bigint(20) NOT NULL COMMENT '预约人userId',`appoint_store_id` bigint(20) NOT NULL COMMENT '预约门店',`appoint_service_type` int(11) DEFAULT NULL COMMENT '预约服务类型(9:儿科查房 7:产科查房 8:中医查房)',`appoint_doctor_id` bigint(11) DEFAULT NULL COMMENT '预约医生id',`appoint_date` date DEFAULT NULL COMMENT '预约日期(精确到日)',`appoint_time_start` time NOT NULL COMMENT '预约开始时间',`appoint_time_end` time NOT NULL COMMENT '预约结束时间',`status` int(11) NOT NULL COMMENT '状态(-1:已取消 0:待接单 1:待分配(已拒绝) 2:待查房 3:待小结 4:待签名 100:已完成 )',`drive_appointment_id` bigint(20) DEFAULT NULL COMMENT '驱动预约单id(null:代表驱动预约单)',`appointment_setting_id` bigint(20) DEFAULT NULL COMMENT '预约单-配置id',`create_id` bigint(20) DEFAULT NULL COMMENT '创建人id',`gmt_create` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`modify_id` bigint(20) DEFAULT NULL COMMENT '修改人',`gmt_modified` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',`deleted` tinyint(1) DEFAULT '0' COMMENT '删除标记;0-正常 ;1-删除',PRIMARY KEY (`id`),KEY `idx_drive_appointment_id` (`drive_appointment_id`) USING BTREE,KEY `idx_appointment_setting_id` (`appointment_setting_id`) USING BTREE,KEY `idx_appoint_user_id` (`appoint_user_id`) USING BTREE
)  AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4  COMMENT='预约单';-- 预约单-状态流转表CREATE TABLE `stbella-his`.appointment_status_log
( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键id',appointment_id    bigint(20)						not null COMMENT '预约单id',before_status 	  int(11)							  NOT null COMMENT '前状态',after_status 	    int(11)							  NOT null COMMENT '后状态',handle_type       int(11)								not null COMMENT '操作类型',handle_user_type    int(11)					    not null COMMENT '操作人类型',create_id bigint(20) DEFAULT NULL COMMENT '创建人id',gmt_create datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',modify_id bigint(20) DEFAULT NULL COMMENT '修改人',gmt_modified datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',deleted tinyint(1) DEFAULT '0' COMMENT '删除标记;0-正常 ;1-删除',PRIMARY KEY (`id`),KEY `idx_appointment_id` (`appointment_id`) USING BTREE
)  comment '预约单-状态流转表'; 

二.状态枚举类

@Getter
@AllArgsConstructor
public enum AppointStatusEnum {INIT(-100, "初始化"),CANCEL(-1, "已取消"),WAIT_RECEIVE(0, "待接单"),WAIT_DISTRIBUTE(1, "待分配"),WAIT_CHECK_ROOM(2, "待查房"),WAIT_SUMMARY(3, "待小结"),WAIT_SIGN(4, "待签名"),COMPLETE(100, "已完成");private final int code;private final String name;public static AppointStatusEnum getEnum(int code) {for (AppointStatusEnum statusEnum : AppointStatusEnum.values()) {if (statusEnum.getCode() == code) {return statusEnum;}}return null;}}

三. 上下文参数类:参数传递

@Builder
@Data
public class AppointContext implements Serializable {private static final long serialVersionUID = 3542771730176821092L;private UserTokenInfoDTO userTokenInfoDTO;private ClientEnum clientEnum;private AppointPO appointPO;}

四.状态机流转上下文类:所有要执行的动作都在这里记录

@Data
public class AppointHandleContext implements Serializable {private static final long serialVersionUID = 1658366511210864400L;private IAppointStatusHandler statusHandler = AppointStatusHandlerFactory.getStatusHandler(AppointStatusEnum.INIT);public AppointDetailVO detail(AppointHandleContext handleContext, public Boolean cancel(AppointHandleContext handleContext, AppointContext context) {return statusHandler.cancel(handleContext, context);}public String add(AppointHandleContext handleContext, AppointContext context) {return statusHandler.add(handleContext, context);}public Boolean update(AppointHandleContext handleContext, AppointContext context) {return statusHandler.update(handleContext, context);}}

五.状态处理器工厂类

@Component
public class AppointStatusHandlerFactory implements ApplicationContextAware {private static final Map<AppointStatusEnum, IAppointStatusHandler> MAP = Maps.newHashMapWithExpectedSize(AppointStatusEnum.values().length);@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {Map<String, IAppointStatusHandler> beansOfType = applicationContext.getBeansOfType(IAppointStatusHandler.class);if (CollectionUtil.isEmpty(beansOfType)) {return;}beansOfType.forEach((key, statusHandler) -> MAP.put(statusHandler.getStatus(), statusHandler));}public static IAppointStatusHandler getStatusHandler(AppointStatusEnum appointStatusEnum) {return Optional.ofNullable(MAP.get(appointStatusEnum)).orElseThrow(() -> new BusinessException(ResultEnum.PARAM_ERROR, "预约单状态异常"));}}

六.状态接口类

public interface IAppointStatusHandler {AppointStatusEnum getStatus();AppointDetailVO detail(AppointHandleContext handleContext, AppointContext context);Boolean cancel(AppointHandleContext handleContext, AppointContext context);String add(AppointHandleContext handleContext, AppointContext context);Boolean update(AppointHandleContext handleContext, AppointContext context);」

七.状态抽象实现类

@Slf4j
@Component
public abstract class AbstractAppointStatusHandler implements IAppointStatusHandler {private static final String LOG_PRE = "预约单状态流转异常,method:{},handleContext:{},context:{}";@Overridepublic AppointDetailVO detail(AppointHandleContext handleContext, AppointContext context) {log.error(LOG_PRE, "detail", JSONUtil.toJsonStr(handleContext), JSONUtil.toJsonStr(context));throw new BusinessException(ResultEnum.PARAM_ERROR, "当前状态不允许查询");}@Overridepublic Boolean cancel(AppointHandleContext handleContext, AppointContext context) {log.error(LOG_PRE, "cancel", JSONUtil.toJsonStr(handleContext), JSONUtil.toJsonStr(context));throw new BusinessException(ResultEnum.PARAM_ERROR, "当前状态不允许取消");}@Overridepublic String add(AppointHandleContext handleContext, AppointContext context) {log.error(LOG_PRE, "add", JSONUtil.toJsonStr(handleContext), JSONUtil.toJsonStr(context));throw new BusinessException(ResultEnum.PARAM_ERROR, "当前状态不允许新增");}@Overridepublic Boolean update(AppointHandleContext handleContext, AppointContext context) {log.error(LOG_PRE, "update", JSONUtil.toJsonStr(handleContext), JSONUtil.toJsonStr(context));throw new BusinessException(ResultEnum.PARAM_ERROR, "当前状态不允许修改");}
}

八.每个状态节点实现类

@Slf4j
@Component
public class AppointInitHandler extends AbstractAppointStatusHandler {@Overridepublic AppointStatusEnum getStatus() {return AppointStatusEnum.INIT;}@Overridepublic AppointDetailVO detail(AppointHandleContext handleContext, AppointContext context) {return appointSupport.detail(context);}@Overridepublic String add(AppointHandleContext handleContext, AppointContext context) {}}
@Slf4j
@Component
public class AppointWaitCheckRoomHandler extends AbstractAppointStatusHandler {@Overridepublic AppointStatusEnum getStatus() {return AppointStatusEnum.WAIT_CHECK_ROOM;}@Resourceprivate AppointSupport appointSupport;@Overridepublic AppointDetailVO detail(AppointHandleContext handleContext, AppointContext context) {AppointDetailVO detail = appointSupport.detail(context);ClientEnum clientEnum = context.getClientEnum();AppointPO appointPO = context.getAppointPO();switch (clientEnum) {case HIS_NURSE:this.nurseDetail(detail, appointPO);break;case HIS_DOCTOR:this.doctorDetail(detail, appointPO);break;default:break;}return detail;}@Overridepublic Boolean cancel(AppointHandleContext handleContext, AppointContext context) {return appointSupport.handleOnlyStatus(context, AppointStatusEnum.CANCEL, AppointHandleTypeEnum.CANCEL);}@Overridepublic Boolean startCheckRoom(AppointHandleContext handleContext, AppointContext context) {return appointSupport.handleOnlyStatus(context, AppointStatusEnum.WAIT_SUMMARY, AppointHandleTypeEnum.START_CHECK_ROOM);}
@Slf4j
@Component
public class AppointCompleteHandler extends AbstractAppointStatusHandler {@Overridepublic AppointStatusEnum getStatus() {return AppointStatusEnum.COMPLETE;}@Overridepublic AppointDetailVO detail(AppointHandleContext handleContext, AppointContext context) {AppointDetailVO detail = appointSupport.detail(context);ClientEnum clientEnum = context.getClientEnum();AppointPO appointPO = context.getAppointPO();switch (clientEnum) {case HIS_NURSE:this.nurseDetail(detail, appointPO);break;case HIS_DOCTOR:this.doctorDetail(detail, appointPO);break;default:break;}return detail;}@Overridepublic AppointCheckRoomSignNotifyVO getAppointCheckRoomSignNotifyVO(AppointHandleContext handleContext, AppointContext context) {}
}

九.具体行为调用代码类

@Overridepublic void bindPicpCustomer(AppointClinicBindReq req, UserTokenInfoDTO userTokenInfoDTO) {AppointPO appointPO = Optional.ofNullable(appointRepository.getOnePOById(req.getAppointmentId())).orElseThrow(() ->new BusinessException(ResultEnum.PARAM_ERROR, "预约单数据不存在或已被删除"));AppointHandleContext handleContext = new AppointHandleContext();handleContext.setStatusHandler(AppointStatusHandlerFactory.getStatusHandler(AppointStatusEnum.getEnum(appointPO.getStatus())));handleContext.bindPicpCustomer(handleContext, AppointContext.builder().appointPO(appointPO).clientEnum(appointSupport.getLoginClientEnum(userTokenInfoDTO)).userTokenInfoDTO(userTokenInfoDTO).picpUsers(req.getPicpUsers()).build());}

相关文章:

设计模式(实战项目)-状态模式

需求背景&#xff1a;存在状态流转的预约单 一.数据库设计 CREATE TABLE appointment (id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 主键id,appoint_type int(11) NOT NULL COMMENT 预约类型(0:线下查房...),appoint_user_id bigint(20) NOT NULL COMMENT 预约人…...

【python】OpenCV—Color Map

文章目录 cv2.applyColorMapcv2.putText小试牛刀自定义颜色 参考学习来自 OpenCV基础&#xff08;21&#xff09;使用 OpenCV 中的applyColorMap实现伪着色 cv2.applyColorMap cv2.applyColorMap() 是 OpenCV 中的一个函数&#xff0c;用于将灰度图像或单通道图像应用一个颜色…...

MySQL:表的内连接和外连接、索引

文章目录 1.内连接2.外连接2.1 左外连接2.2 右外连接 3.综合练习4.索引4.1见一见索引4.2 硬件理解4.3 MySQL 与磁盘交互基本单位(软件理解)4.4 (MySQL选择的数据结构)索引的理解4.5 聚簇索引 VS 非聚簇索引 5.索引操作5.1 创建索引5.2 查询索引5.3 删除索引 1.内连接 内连接实…...

Chrome备份数据

Chrome备份数据 1、 导出谷歌浏览器里的历史记录 参考&#xff1a;https://blog.csdn.net/qq_32824605/article/details/127504219 在资源管理器中找到History文件&#xff0c;文件路径&#xff1a; C:\Users\你的电脑用户名\AppData\Local\Google\Chrome\User Data\Default …...

visual studio远程调试

场景一&#xff08;被远程调试的电脑&#xff09; 确定系统位数 我这里是x64的 找到msvsmon.exe msvsmon.exe目录位置解释&#xff1a; “F:\App\VisualStudio\an\Common7\IDE\”是visual studio所在位置、 “Remote Debugger\”是固定位置、 “x64”是系统位数。 拼起来就是…...

if __name__ == “__main__“

在Python中&#xff0c;if __name__ "__main__": 这行代码非常常见&#xff0c;它用于判断当前运行的脚本是否是主程序。这里的 __name__ 是一个特殊变量&#xff0c;当Python文件被直接运行时&#xff0c;__name__ 被自动设置为字符串 "__main__"。但是&…...

数据识别概述

数据识别场景 数据识别确实可以分为两种主要类型&#xff1a;直接识别和间接识别&#xff08;或称为从文本中发现&#xff09;。下面我将详细解释这两种类型&#xff1a; 直接识别&#xff1a; 定义&#xff1a;直接识别是指直接判断某个数据是否符合特定的标准或条件。应用场…...

pytorch统计学分布

1、pytorch统计学函数 import torcha torch.rand(2,2) print(a) print(torch.sum(a, dim0)) print(torch.mean(a, dim0)) print(torch.prod(a, dim0))print(torch.argmax(a, dim0)) print(torch.argmin(a, dim0)) print(torch.std(a)) print(torch.var(a)) print(torch.median…...

【网络安全学习】漏洞利用:BurpSuite的使用-03-枚举攻击案例

如何使用BurpSuite进行枚举攻击 1.靶场选择 BurpSuite官方也是有渗透的教学与靶场的&#xff0c;这次就使用BurpSuite的靶场进行练习。 靶场地址&#xff1a;https://portswigger.net/web-security 登录后如下图所示&#xff0c;选择**【VIEW ALL PATHS】**&#xff1a; 找…...

redis 消息订阅命令

在 Redis 中&#xff0c;消息订阅和发布是一种用于实现消息传递的机制。主要命令包括 SUBSCRIBE、UNSUBSCRIBE、PUBLISH 和 PSUBSCRIBE 等。下面是如何使用这些命令的详细说明和示例。 1. SUBSCRIBE 命令 SUBSCRIBE 命令用于订阅一个或多个频道&#xff0c;以接收这些频道发布…...

springboot接口防抖【防重复提交】

什么是防抖 所谓防抖&#xff0c;一是防用户手抖&#xff0c;二是防网络抖动。在Web系统中&#xff0c;表单提交是一个非常常见的功能&#xff0c;如果不加控制&#xff0c;容易因为用户的误操作或网络延迟导致同一请求被发送多次&#xff0c;进而生成重复的数据记录。要针对用…...

每日一题——Python实现PAT乙级1026 程序运行时间(举一反三+思想解读+逐步优化)五千字好文

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 我的写法 代码结构和逻辑 时间复杂度 空间复杂度 代码优化建议 总结 我要更强 …...

还在Excel中管理您的持续改进项目吗?

对于大多数公司来说&#xff0c;Microsoft Excel是一种可靠的资源&#xff0c;它确实提供了极高的价值。然而&#xff0c;当它被用来跟踪持续改进项目时&#xff0c;它的价值就减少了。浪费时间从不同内部系统的不同报告中收集数据&#xff0c;会占用推动重要变革的时间。让我们…...

CentOS 7 内存占用过大导致 OOM Killer 杀掉了 Java 进程

说明 Linux进程被杀掉&#xff08;OOM killer&#xff09;&#xff0c;查看系统日志 oom killer 详解 测试服务器, 有一个 Java 应用, 其进程偶尔会消失掉, 已排除人为杀死的可能 该服务器内存常年处于快被占满的状态, 怀疑是内存原因, 导致服务器主动杀死了该应用的 Java 进程…...

在postgrel中使用hints

在 PostgreSQL 中&#xff0c;可以使用查询提示&#xff08;Query Hints&#xff09;来影响查询优化器的行为&#xff0c;但需要注意的是&#xff0c;PostgreSQL 并不像一些商业数据库那样有丰富的提示语法&#xff0c;而是提供了一些基本的方式来引导优化器。 使用查询提示的…...

OceanBase Meetup北京站|跨行业应用场景中的一体化分布式数据库:AI赋能下的探索与实践

随着业务规模的不断扩张和数据处理需求的日益复杂化&#xff0c;传统数据库架构逐渐暴露出业务稳定性波动、扩展性受限、处理效率降低以及运营成本高等一系列问题。众多行业及其业务场景纷纷踏上了数据库现代化升级之路。 为应对这些挑战&#xff0c;7月6日&#xff0c;OceanB…...

Spring Boot:轻松设置全局异常处理

Spring Boot&#xff1a;轻松设置全局异常处理 在软件开发中&#xff0c;异常处理是一项至关重要的任务。对于使用Spring Boot的开发者来说&#xff0c;设置全局异常处理不仅可以提高代码的整洁度&#xff0c;还可以提升用户体验。本文将详细介绍如何在Spring Boot中轻松设置全…...

Omni3D目标检测

Omni3D是一个针对现实场景中的3D目标检测而构建的大型基准和模型体系。该项目旨在推动从单一图像中识别3D场景和物体的能力&#xff0c;这对于计算机视觉领域而言是一个长期的研究目标&#xff0c;并且在机器人、增强现实&#xff08;AR&#xff09;、虚拟现实&#xff08;VR&a…...

前端三件套开发模版——产品介绍页面

今天有空&#xff0c;使用前端三件套html、css、js制作了一个非常简单的产品制作页面&#xff0c;与大家分享&#xff0c;希望可以满足大家应急的需求。本页面可以对产品进行“抢购”、对产品进行介绍&#xff0c;同时可以安排一张产品的高清大图&#xff0c;我也加入了页面的背…...

Android Bitmap 和Drawable的区别

Bitmap 和 Drawable 是 Android 图形绘制的两种常用方式&#xff0c;它们有各自的特点和使用场景。下面将详细解释它们之间的区别&#xff0c;并通过示例代码说明如何使用它们。 Bitmap 解释 Bitmap 是一种用于存储图像像素数据的类&#xff0c;通常用于图像处理和操作。Bit…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来

一、破局&#xff1a;PCB行业的时代之问 在数字经济蓬勃发展的浪潮中&#xff0c;PCB&#xff08;印制电路板&#xff09;作为 “电子产品之母”&#xff0c;其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透&#xff0c;PCB行业面临着前所未有的挑战与机遇。产品迭代…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

srs linux

下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935&#xff0c;SRS管理页面端口是8080&#xff0c;可…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文全面剖析RNN核心原理&#xff0c;深入讲解梯度消失/爆炸问题&#xff0c;并通过LSTM/GRU结构实现解决方案&#xff0c;提供时间序列预测和文本生成…...

【Go语言基础【13】】函数、闭包、方法

文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数&#xff08;函数作为参数、返回值&#xff09; 三、匿名函数与闭包1. 匿名函数&#xff08;Lambda函…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...