liusheng
昨天 b57304d9917beab4671442a0018c1c3a2d681640
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package com.smartor.statemachine;
 
/**
 * 住院状态机使用示例
 * 
 * 本类展示如何在现有代码中集成状态机,仅供参考,不需要运行
 * 
 * @author smartor
 */
public class InhospStateMachineExample {
 
    /**
     * 示例1: 在ServiceSLTDHealthcareRecordServiceImpl中使用状态机
     * 
     * 原方法签名:
     * private void processPatientInhospInfo(ServiceSLTDInhospResDTO dto, PatArchive patArchive, String cry)
     * 
     * 改造方案:用状态机替换原有的if-else逻辑
     */
    public void exampleUsageInService() {
        /*
        // 原代码(561-677行)改造为:
        
        @Autowired
        private InhospStateMachineService stateMachineService;
        
        private void processPatientInhospInfo(ServiceSLTDInhospResDTO dto, PatArchive patArchive, String cry) {
            // 构建住院记录对象(保持原有逻辑)
            PatMedInhosp patMedInhosp = buildPatientInhospInfo(dto, patArchive, cry);
            
            // 使用状态机处理状态转换(替换原有的大段if-else)
            boolean success = stateMachineService.processStateChange(patMedInhosp, cry);
            
            if (success) {
                log.info("【processPatientInhospInfo】状态转换成功:serialnum={}, cry={}", 
                        patMedInhosp.getSerialnum(), cry);
            } else {
                log.warn("【processPatientInhospInfo】状态转换失败或跳过:serialnum={}, cry={}", 
                        patMedInhosp.getSerialnum(), cry);
            }
        }
        
        // 优点:
        // 1. 代码从100+行减少到10行
        // 2. 状态转换逻辑清晰,易于维护
        // 3. 自动加分布式锁,解决并发问题
        // 4. 状态校验规则集中管理
        */
    }
 
    /**
     * 示例2: 直接使用状态机服务API
     */
    public void exampleDirectUsage() {
        /*
        @Autowired
        private InhospStateMachineService stateMachineService;
        
        // 处理预入院
        PatMedInhosp preAdmission = new PatMedInhosp();
        preAdmission.setSerialnum("202601290001");
        preAdmission.setOrgid("HOS001");
        preAdmission.setPatno("P001");
        // ... 设置其他字段
        
        boolean result1 = stateMachineService.processPreAdmission(preAdmission);
        
        // 处理入院(会自动从预入院状态转换)
        PatMedInhosp inHospital = new PatMedInhosp();
        inHospital.setSerialnum("202601290001");
        inHospital.setOrgid("HOS001");
        inHospital.setPatno("P001");
        // ... 设置其他字段
        
        boolean result2 = stateMachineService.processInHospital(inHospital);
        
        // 处理出院(会自动从入院状态转换)
        PatMedInhosp discharge = new PatMedInhosp();
        discharge.setSerialnum("202601290001");
        discharge.setOrgid("HOS001");
        discharge.setPatno("P001");
        // ... 设置其他字段
        
        boolean result3 = stateMachineService.processDischarge(discharge);
        
        // 查询当前状态
        String currentState = stateMachineService.getCurrentState("202601290001", "HOS001", "P001");
        // currentState = "1" (出院状态)
        */
    }
 
    /**
     * 示例3: 状态转换校验
     */
    public void exampleStateValidation() {
        /*
        // 非法转换示例1:预入院直接到出院(会抛出异常)
        try {
            PatMedInhosp discharge = new PatMedInhosp();
            discharge.setSerialnum("202601290002");
            discharge.setOrgid("HOS001");
            discharge.setPatno("P002");
            discharge.setInhospstate("3"); // 当前是预入院
            
            stateMachineService.processDischarge(discharge); // 尝试直接出院
            
        } catch (StateTransitionException e) {
            log.error("状态转换失败:{}", e.getMessage());
            // 输出: 非法的状态转换: 从 [3] 到 [1]
        }
        
        // 非法转换示例2:重复入院(会被handler拒绝)
        PatMedInhosp inHospital1 = new PatMedInhosp();
        inHospital1.setSerialnum("202601290003");
        inHospital1.setOrgid("HOS001");
        inHospital1.setPatno("P003");
        
        stateMachineService.processInHospital(inHospital1); // 第一次入院:成功
        
        boolean result = stateMachineService.processInHospital(inHospital1); // 第二次入院:失败
        // result = false,日志输出警告
        */
    }
 
    /**
     * 状态机架构说明
     * 
     * 1. 状态枚举 (InhospStateEnum)
     *    - 定义所有状态及允许的转换规则
     *    - PRE_ADMISSION(3) -> IN_HOSPITAL(0) -> DISCHARGED(1)
     * 
     * 2. 状态处理器 (InhospStateHandler)
     *    - PreAdmissionHandler: 处理预入院逻辑
     *    - InHospitalHandler: 处理入院逻辑
     *    - DischargeHandler: 处理出院逻辑
     * 
     * 3. 状态机管理器 (InhospStateMachine)
     *    - 协调状态转换
     *    - 管理分布式锁
     *    - 验证状态合法性
     * 
     * 4. 门面服务 (InhospStateMachineService)
     *    - 提供便捷API
     *    - 封装复杂逻辑
     * 
     * 5. 异常处理 (StateTransitionException)
     *    - 处理非法状态转换
     */
 
    /**
     * 数据库配合建议
     * 
     * 1. 添加唯一索引(建议)
     * CREATE UNIQUE INDEX uk_serialnum_orgid_state 
     * ON pat_med_inhosp(serialnum, orgid, inhospstate);
     * 
     * 2. 或者更严格的约束(确保一个患者只有一条记录)
     * CREATE UNIQUE INDEX uk_serialnum_orgid 
     * ON pat_med_inhosp(serialnum, orgid);
     * 
     * 注意:如果使用第2种索引,需要确保:
     * - 状态变更必须走更新(不能插入新记录)
     * - 需要清理历史多状态记录
     */
 
    /**
     * 渐进式集成方案
     * 
     * 阶段1:双写模式(推荐)
     * - 保留原有代码不变
     * - 新增状态机调用,记录日志对比
     * - 验证状态机逻辑正确性
     * 
     * 阶段2:灰度切换
     * - 部分cry值走状态机
     * - 观察生产环境表现
     * 
     * 阶段3:完全迁移
     * - 全部逻辑切换到状态机
     * - 移除原有if-else代码
     */
}