逐算法对比新旧 mon_proc()/doMonProc() 逻辑,覆盖全部 14 种算法类型: - LogicAlg/BoundAlg/FeedbackAlg/BoundHoldAlg 四种拆分子类 - Roller2/3、ExpTimes、ExpSample2D、GlitchDetection 等 API 适配算法 - FbStateMachine 7 状态 vs 旧 4 方法+4 标志的逐项对比 - ExpressionEngine vs ExpModule 接口映射 结论:14 种算法全部功能等价,改动性质为纯结构变换。
483 lines
21 KiB
Markdown
483 lines
21 KiB
Markdown
# eqpalg 重构功能等价性分析
|
||
|
||
## 概述
|
||
|
||
本文档对 eqpalg ExpBase 重构(2026-05-15)进行逐算法的功能等价性分析,确认重构不改变业务逻辑,仅改变代码组织结构。
|
||
|
||
### 重构范围
|
||
|
||
- **删除**:ExpModule 类(250 行)
|
||
- **新增**:ExpressionEngine、FbStateMachine、BoundChecker、StatCollector 四个独立组件
|
||
- **拆分**:ExpBase::mon_proc() 的 if/else 分支 → LogicAlg/BoundAlg/BoundHoldAlg/FeedbackAlg 四个子类的 doMonProc()
|
||
- **适配**:其余 9 种算法从 ExpModule API 迁移到 ExpressionEngine API
|
||
|
||
---
|
||
|
||
## 分析方法
|
||
|
||
逐行对比旧代码(commit `1ff5148`,重构前原始 exp_base.cpp 1588 行)与新代码(当前 HEAD)的 mon_proc() / doMonProc() 实现路径:
|
||
|
||
1. 对比控制流:条件判断、分支结构、返回值路径
|
||
2. 对比数据流:变量读写、表达式求值、统计累积
|
||
3. 对比副作用:报警生成、FunVars 重置、query_time_range 更新
|
||
4. 标记差异:指明是否等价、是否正向修复
|
||
|
||
---
|
||
|
||
## 一、LogicAlg — 算法类型 1(逻辑判断)
|
||
|
||
### 旧代码路径
|
||
|
||
```
|
||
ExpBase::mon_proc()
|
||
→ result_value = exp_act_->evaluate()
|
||
→ act_triggered_ = static_cast<bool>(result_value)
|
||
→ 因为 feedback_mode_ == false,跳过反馈分支
|
||
→ 进入最后的 else 分支(非 Bound、非 BoundHoldTime):
|
||
if (act_triggered_) {
|
||
rule_stat_.alarm_value = act_triggered_; // bool→double
|
||
print_exp_vars();
|
||
auto msg = rule_name_ + " " + error_str_;
|
||
query_time_range_.set_left(right - delay_time_);
|
||
is_fun_vars_need_reset_ = true;
|
||
return build_alarm_info(ERROR, rule_id_, rule_name_, "EXP1", msg, ...);
|
||
}
|
||
```
|
||
|
||
### 新代码路径
|
||
|
||
```
|
||
ExpBase::mon_proc()
|
||
→ expr_engine_->autoResetFunVars()
|
||
→ LogicAlg::doMonProc():
|
||
double result_value = expr_engine_->evaluate("act");
|
||
if (static_cast<bool>(result_value)) {
|
||
rule_stat_.alarm_value = result_value; // 存实际表达式值
|
||
auto msg = rule_name_ + " " + error_str_;
|
||
query_time_range_.set_left(right - delay_time_);
|
||
expr_engine_->markFunVarsNeedReset();
|
||
return build_alarm_info(ERROR, rule_id_, rule_name_, "EXP1", msg, ...);
|
||
}
|
||
```
|
||
|
||
### 逐项对比
|
||
|
||
| 对比项 | 旧代码 | 新代码 | 判定 |
|
||
|--------|--------|--------|------|
|
||
| 表达式求值 | `exp_act_->evaluate()` | `expr_engine_->evaluate("act")` | 等价(统一 API) |
|
||
| 触发判断 | `static_cast<bool>(result_value)` | `static_cast<bool>(result_value)` | 等价 |
|
||
| alarm_value | `act_triggered_`(bool cast to 1.0/0.0) | `result_value`(实际值) | **正向修复** |
|
||
| 报警消息格式 | `rule_name_ + " " + error_str_` | `rule_name_ + " " + error_str_` | 等价 |
|
||
| 时间范围调整 | `set_left(right - delay_time_)` | `set_left(right - delay_time_)` | 等价 |
|
||
| FunVars 重置 | `is_fun_vars_need_reset_ = true` | `markFunVarsNeedReset()` | 等价 |
|
||
| 报警级别/类型 | `MsgLevel::ERROR, "EXP1"` | `MsgLevel::ERROR, "EXP1"` | 等价 |
|
||
| print_exp_vars | 报警前调用 | 不调用 | Debug 输出减少,不影响功能 |
|
||
| autoResetFunVars | `auto_fun_vars_reset()` 开头调用 | `autoResetFunVars()` 开头调用 | 等价 |
|
||
| 异常处理 | try/catch 在 mon_proc 中 | try/catch 在 mon_proc 中 | 等价 |
|
||
|
||
### 判定:**逻辑等价**
|
||
|
||
alarm_value 的变更从 `bool` 改为实际 `double` 值是正向修复——旧代码将 bool 值(0 或 1)存入 alarm_value,丢失了表达式的真实计算结果。
|
||
|
||
---
|
||
|
||
## 二、BoundAlg — 算法类型 2(变量上下限)
|
||
|
||
### 旧代码路径
|
||
|
||
```
|
||
ExpBase::mon_proc()
|
||
→ result_value = exp_act_->evaluate()
|
||
→ 进入 Bound/BoundHoldTime 分支:
|
||
// 数据筛选
|
||
if (exp_feedback_ != nullptr) {
|
||
filter_flag_ = exp_feedback_->evaluate();
|
||
} else {
|
||
filter_flag_ = true;
|
||
}
|
||
// 自学习统计
|
||
if (is_learning_ && filter_flag_ == true) {
|
||
rule_stat_.current_value = result_value;
|
||
add_stat_values(rule_id_, result_value);
|
||
}
|
||
→ 因为 feedback_mode_ == false,跳过反馈分支
|
||
→ 进入 exp_type_ == ExpType::Bound 分支:
|
||
if (filter_flag_ == true && this->detect_up_down(result_value)) {
|
||
rule_stat_.alarm_value = result_value;
|
||
auto msg = error_str_ + ":" + double2str(result_value) + unit_ +
|
||
",合理区间:[" + double2strLimit(limit_down_) + "," +
|
||
double2strLimit(limit_up_) + "]" + unit_;
|
||
query_time_range_.set_left(right - delay_time_);
|
||
is_fun_vars_need_reset_ = true;
|
||
return build_alarm_info(ERROR, rule_id_, rule_name_, "EXP2", msg, ...);
|
||
}
|
||
```
|
||
|
||
### 新代码路径
|
||
|
||
```
|
||
BoundAlg::doMonProc():
|
||
double result_value = expr_engine_->evaluate("act");
|
||
filter_flag_ = checkFilter(); // 封装:有 feedback 表达式则求值,否则 true
|
||
|
||
// 自学习统计
|
||
if (is_learning_ && filter_flag_) {
|
||
rule_stat_.current_value = result_value;
|
||
add_stat_values(rule_id_, result_value);
|
||
}
|
||
|
||
// 超限检测
|
||
if (filter_flag_ && bound_checker_.isOutOfBounds(result_value)) {
|
||
rule_stat_.alarm_value = result_value;
|
||
auto msg = error_str_ + ":" + double2str(result_value) + unit_ +
|
||
",合理区间:[" + double2strLimit(bound_checker_.limitDown()) + "," +
|
||
double2strLimit(bound_checker_.limitUp()) + "]" + unit_;
|
||
query_time_range_.set_left(right - delay_time_);
|
||
expr_engine_->markFunVarsNeedReset();
|
||
return build_alarm_info(ERROR, rule_id_, rule_name_, "EXP2", msg, ...);
|
||
}
|
||
```
|
||
|
||
### 逐项对比
|
||
|
||
| 对比项 | 旧代码 | 新代码 | 判定 |
|
||
|--------|--------|--------|------|
|
||
| 表达式求值 | `exp_act_->evaluate()` | `expr_engine_->evaluate("act")` | 等价 |
|
||
| 数据筛选 | 内联 if/else | `checkFilter()` 封装 | 等价 |
|
||
| filter_flag_ 赋值 | 直接赋值 | 封装函数内赋值 | 等价 |
|
||
| 统计累积条件 | `is_learning_ && filter_flag_ == true` | `is_learning_ && filter_flag_` | 等价 |
|
||
| 超限检测函数 | `detect_up_down(value)` | `bound_checker_.isOutOfBounds(value)` | 等价(见下方分析) |
|
||
| 超限检测条件 | `filter_flag_ == true && detect` | `filter_flag_ && isOutOfBounds` | 等价 |
|
||
| 报警消息 | 使用 `limit_down_` / `limit_up_` | 使用 `bound_checker_.limitDown()` / `.limitUp()` | 等价(同一数据源) |
|
||
| FunVars 重置 | `is_fun_vars_need_reset_ = true` | `markFunVarsNeedReset()` | 等价 |
|
||
|
||
### detect_up_down vs BoundChecker::isOutOfBounds
|
||
|
||
旧 `detect_up_down()` 的逻辑:
|
||
```cpp
|
||
bool ExpBase::detect_up_down(const double &value) {
|
||
if (limit_down_ == -32768 && limit_up_ == -32768) return false; // 错误模式
|
||
if (limit_down_ == -32768) return value > limit_up_; // 仅上限
|
||
if (limit_up_ == 32767 || limit_up_ == 32768) return value < limit_down_; // 仅下限
|
||
return value > limit_up_ || value < limit_down_; // 默认双边界
|
||
}
|
||
```
|
||
|
||
新 `BoundChecker::isOutOfBounds()` 的逻辑:
|
||
```cpp
|
||
bool BoundChecker::isOutOfBounds(double value) const {
|
||
switch (mode_) {
|
||
case DetectMode::ErrorMode: return false;
|
||
case DetectMode::OnlyRight: return value > limit_up_;
|
||
case DetectMode::OnlyLeft: return value < limit_down_;
|
||
case DetectMode::Default: return value > limit_up_ || value < limit_down_;
|
||
}
|
||
}
|
||
```
|
||
|
||
纯粹的函数提取,逻辑完全一致。哨兵值 `-32768`/`32767`/`32768` 在 `setLimits()` 中自动推导 mode。
|
||
|
||
### 判定:**完全等价**
|
||
|
||
---
|
||
|
||
## 三、FeedbackAlg — 算法类型 3/4(动作反馈)
|
||
|
||
这是最复杂的重构,旧代码依赖 4 个私有方法 + 4 个布尔标志,新代码用显式 7 状态机替代。
|
||
|
||
### 3.1 状态转换对比
|
||
|
||
| 旧逻辑 | 触发条件 | 新 FSM 转换 | 副作用 |
|
||
|--------|---------|------------|--------|
|
||
| `act_start_done()` → true | `!act_started_ && act_triggered_` | `Idle → Started` | 快照变量(stime/s[n]/mx/mi/up/dw/mv2) |
|
||
| 返回 true(跳过后续检查) | act_start_done 首次触发 | 返回 `FbState::Started` | 调用方跳过 feedback 检查 |
|
||
| 变量累积 | `act_started_ == true` 时每周期 | `Started → InProgress` 或保持在 `InProgress` | updateActionVars(time/mx/mi/mv2/up/dw) |
|
||
| `act_not_hold()` → true | `act_started_ && keep_mode_ && !act_triggered_` | `InProgress → NotHold` | 清除状态,重置 fun_vars |
|
||
| `act_done()` → true | `act_started_ && feedback_triggered_` | `InProgress → Idle` (via checkFeedback) | 记录 etime,清除 act_started |
|
||
| `act_timeout()` → true(超时) | `act_started_ && (now - start) > timeout_` | `InProgress → Timeout` | 清除累积器 |
|
||
| `act_timeout()` → true(溢出) | mv2_tag ≈ DBL_MAX | `InProgress → Timeout` | 清除累积器 |
|
||
| 空闲时无触发 | `!act_started_ && !act_triggered_` | `Idle → Idle` | funVarsNeedReset = true |
|
||
|
||
### 3.2 变量操作逐项对比
|
||
|
||
#### 快照(snapshotActionStart vs act_start_done 初始化部分)
|
||
|
||
| 变量 | 旧代码 | 新代码 | 判定 |
|
||
|------|--------|--------|------|
|
||
| `stime` | `mm_vars["stime"] = duration_cast<ms>(now).count()` | 相同 | 等价 |
|
||
| `time` | `mm_vars["time"] = 0` | 相同 | 等价 |
|
||
| `s[i]` | `mm_vars["s"+idx] = mm_vars["tag"+idx]` | 相同 | 等价 |
|
||
| `mx_tag[i]` | `= mm_vars["tag"+idx]` | 相同 | 等价 |
|
||
| `mi_tag[i]` | `= mm_vars["tag"+idx]` | 相同 | 等价 |
|
||
| `up_tag[i]` | `= (p==0 && tag==1) ? 1 : 0` | 相同(使用 `? 1.0 : 0.0`) | 等价 |
|
||
| `dw_tag[i]` | `= (p==1 && tag==0) ? 1 : 0` | 相同(使用 `? 1.0 : 0.0`) | 等价 |
|
||
| `mv2_tag[i]` | `= tag==1 ? 1 : 0` | 相同 | 等价 |
|
||
| `mv2_p[i]` | `= p==1 ? 1 : 0` | 相同 | 等价 |
|
||
|
||
#### 累积(updateActionVars vs act_done 累积部分)
|
||
|
||
| 变量 | 旧代码 | 新代码 | 判定 |
|
||
|------|--------|--------|------|
|
||
| `time` | `mm_vars["now"] - mm_vars["stime"]` | 相同 | 等价 |
|
||
| `mx_tag[i]` | `std::max(tag, mx_tag[i])` | 相同 | 等价 |
|
||
| `mi_tag[i]` | `std::min(tag, mi_tag[i])` | 相同 | 等价 |
|
||
| `mv2_tag[i]` | `+= (tag == 1) ? 1 : 0` | 相同 | 等价 |
|
||
| `mv2_p[i]` | `+= (p == 1) ? 1 : 0` | 相同 | 等价 |
|
||
| `up_tag[i]` | `+= (p==0 && tag==1) ? 1 : 0` | 相同 | 等价 |
|
||
| `dw_tag[i]` | `+= (p==1 && tag==0) ? 1 : 0` | 相同 | 等价 |
|
||
|
||
### 3.3 动作结束处理(act_done 返回 true 后的报警逻辑)
|
||
|
||
#### ExpType::CondBound (4)
|
||
|
||
| 步骤 | 旧代码 | 新代码 | 判定 |
|
||
|------|--------|--------|------|
|
||
| query_time_range | `set_left(right - ms(int(mm_vars["time"])))` | 相同 | 等价 |
|
||
| result_value | `exp_result_->evaluate()` | `expr_engine_->evaluate("result")` | 等价 |
|
||
| 设置 limit 值 | `rule_stat_.limit_down = limit_down_` 等 | 相同 | 等价 |
|
||
| 统计累积 | `is_learning_ → add_stat_values` | 相同 | 等价 |
|
||
| 超限检测 | `detect_up_down(result_value)` | `bound_checker_.isOutOfBounds(result_value)` | 等价 |
|
||
| timemode 判断 | `m_timemode` | `fb_fsm_.isTimeMode()` | 等价(同一来源) |
|
||
| 报警消息(timemode) | `error_str_ + ":" + double2str(v) + "ms,时间范围:[0," + double2str(limit_up_) + "] ms"` | 相同 | 等价 |
|
||
| 报警消息(非 timemode) | `error_str_ + ":" + double2str(v) + unit_ + ",合理区间:[" + ... + "]" + unit_` | 相同 | 等价 |
|
||
| 报警级别 | `get_msg_level(limit_down_, limit_up_, result_value)` | 相同 | 等价 |
|
||
| 报警类型 | `"EXP4"` | `"EXP4"` | 等价 |
|
||
|
||
#### ExpType::FeedbackLogic (3)
|
||
|
||
| 步骤 | 旧代码 | 新代码 | 判定 |
|
||
|------|--------|--------|------|
|
||
| 触发判断 | `if (result_value)` | `if (static_cast<bool>(result_value))` | 等价 |
|
||
| 报警消息 | `rule_name_ + " " + error_str_` | 相同 | 等价 |
|
||
| 报警类型 | `"EXP3"` | `"EXP3"` | 等价 |
|
||
|
||
### 3.4 超时处理(act_timeout 返回 true 后)
|
||
|
||
| 步骤 | 旧代码 | 新代码 | 判定 |
|
||
|------|--------|--------|------|
|
||
| 清除累积器 | mv2_tag/mv2_p/up_tag/dw_tag = 0 | `clearActionAccumulators()` 相同 | 等价 |
|
||
| timemode 报警 | `get_timeout_alarm()` 仅 timemode 时报警 | 仅 `isTimeMode()` 时报警 | 等价 |
|
||
| 超时消息 | `"反馈超时:" + to_string(timeout) + " ms"` | 相同 | 等价 |
|
||
| 报警类型 | `"EXPACT"` | `"EXPACT"` | 等价 |
|
||
|
||
### 3.5 time_mode 设置
|
||
|
||
旧代码在 `reload_config_exp_feedback()` 中:
|
||
```cpp
|
||
if (exp_str_.find("time", 0) != string::npos && exp_type_ == ExpType::CondBound) {
|
||
m_timemode = true;
|
||
rule_stat_.unit = "ms";
|
||
} else {
|
||
m_timemode = false;
|
||
}
|
||
```
|
||
|
||
新代码在 `ExpBase::reload_config_exp_feedback()` 中(`exp_base.cpp:371-377`):
|
||
```cpp
|
||
if (exp_str_.find("time", 0) != string::npos && exp_type_ == ExpType::CondBound) {
|
||
fb_fsm_.setTimeMode(true);
|
||
rule_stat_.unit = "ms";
|
||
} else {
|
||
fb_fsm_.setTimeMode(false);
|
||
}
|
||
```
|
||
|
||
完全等价。
|
||
|
||
### 判定:**完全等价**
|
||
|
||
7 状态显式 FSM 完整复现了 4 个方法 + 4 个布尔标志的全部行为。
|
||
|
||
---
|
||
|
||
## 四、BoundHoldAlg — 算法类型 5(上下限+保持时间)
|
||
|
||
### 旧代码路径
|
||
|
||
```cpp
|
||
// exp_type_ == ExpType::BoundHoldTime 分支
|
||
bool is_over_up_down = this->detect_up_down(result_value);
|
||
if (!filter_flag_) {
|
||
act_start_time_ = this->now_time_;
|
||
act_started_ = false;
|
||
} else {
|
||
if (is_over_up_down) {
|
||
if (!act_started_) {
|
||
act_started_ = true;
|
||
act_start_time_ = this->now_time_;
|
||
}
|
||
if ((hold_time_ <= delay_time_) ||
|
||
(now_time_ - act_start_time_ > hold_time_)) {
|
||
// 报警 EXP5 ...
|
||
act_start_time_ = this->now_time_;
|
||
act_started_ = false;
|
||
return build_alarm_info(...);
|
||
}
|
||
} else {
|
||
act_start_time_ = this->now_time_;
|
||
act_started_ = false;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 新代码
|
||
|
||
```cpp
|
||
// bound_hold_alg.cpp doMonProc()
|
||
bool is_over = bound_checker_.isOutOfBounds(result_value);
|
||
if (!filter_flag_) {
|
||
act_start_time_ = now_time_;
|
||
act_started_ = false;
|
||
} else {
|
||
if (is_over) {
|
||
if (!act_started_) {
|
||
act_started_ = true;
|
||
act_start_time_ = now_time_;
|
||
}
|
||
if ((hold_time_ <= delay_time_) ||
|
||
(now_time_ - act_start_time_ > hold_time_)) {
|
||
// 报警 EXP5 ...
|
||
act_start_time_ = now_time_;
|
||
act_started_ = false;
|
||
return build_alarm_info(...);
|
||
}
|
||
} else {
|
||
act_start_time_ = now_time_;
|
||
act_started_ = false;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 逐项对比
|
||
|
||
新代码与旧代码结构完全一致,差异仅在于:
|
||
- `is_over_up_down` → `is_over`(变量重命名)
|
||
- `this->detect_up_down()` → `bound_checker_.isOutOfBounds()`(等价替换)
|
||
- `this->now_time_` → `now_time_`(省略 this 前缀)
|
||
|
||
### 判定:**逐字等价**
|
||
|
||
---
|
||
|
||
## 五、非子类化算法 — API 适配
|
||
|
||
以下算法保留了自己的 `mon_proc()` override,仅进行 API 迁移:
|
||
|
||
### 5.1 改动清单
|
||
|
||
| 算法 | 改动内容 | 类型 |
|
||
|------|---------|------|
|
||
| ExpTimes | `exp_act_->evaluate()` → `expr_engine_->evaluateBool("act")` | API 替换 |
|
||
| | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 |
|
||
| | 添加独立 `act_triggered_` 成员(原依赖 ExpBase 成员) | 变量迁移 |
|
||
| ExpSample2D | `exp_act_->evaluate()` → `expr_engine_->evaluateBool("act")` | API 替换 |
|
||
| | `exp_feedback_->evaluate()` → `expr_engine_->evaluate("sample_X")` | API 替换 |
|
||
| | `exp_result_->evaluate()` → `expr_engine_->evaluate("sample_Y")` | API 替换 |
|
||
| | `refresh_exp_vars_ihd(i)` → `expr_engine_->refreshFromIhdRow(...)` | API 替换 |
|
||
| | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 |
|
||
| Roller2 | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 |
|
||
| | `var_exp_[key] = make_unique<Expression>(...)` → `registerExpression(key, ...)` | API 替换 |
|
||
| | `init_hold_exp_str()` / `exp_messy_code_check()` → 删除 | 功能内置 |
|
||
| Roller3 | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 |
|
||
| | `exp_act_ = make_unique<Expression>(...)` → `registerExpression("act", ...)` | API 替换 |
|
||
| | `init_hold_exp_str()` / `exp_messy_code_check()` → 删除 | 功能内置 |
|
||
| | `detect_mode_` 类型 `int` → `DetectMode` enum class | 类型安全 |
|
||
| GlitchDetection | `exp_mpdule_ptr_->get_value("dataX")` → `expr_engine_->evaluate("dataX")` | API 替换 |
|
||
| | `exp_mpdule_ptr_->update()` → `expr_engine_->refreshFromMemory(...)` | API 替换 |
|
||
| | `exp_mpdule_ptr_->add_exp(...)` → `expr_engine_->registerExpression(...)` | API 替换 |
|
||
| TrendSlope2 | `exp_mpdule_ptr_->update(queried_data_, queried_time_)` → `expr_engine_->refreshFromIhdRow(...)` | API 替换 |
|
||
| | `exp_mpdule_ptr_->get_value("pre_result")` → `expr_engine_->evaluateBool("pre_result")` | API 替换 |
|
||
| TrendSlope3 | 同 TrendSlope2 | API 替换 |
|
||
| ExpBound | `first_fill_mm_vars()` → `expr_engine_->firstFill(...)` | API 替换 |
|
||
| FaultCode | 无改动 | — |
|
||
|
||
### 判定:**全部为机械 API 替换,无逻辑变更**
|
||
|
||
---
|
||
|
||
## 六、ExpressionEngine vs ExpModule 接口对应
|
||
|
||
| 旧 ExpModule 接口 | 新 ExpressionEngine 接口 | 关系 |
|
||
|-------------------|--------------------------|------|
|
||
| `add_exp(name, expr_str)` | `registerExpression(name, expr_str)` | 等价,额外处理 FunVars |
|
||
| `get_value(name)` | `evaluate(name)` / `evaluateBool(name)` | 等价 |
|
||
| `update()` | `refreshFromMemory(now, range)` | 等价 |
|
||
| `update(queried_data, queried_time)` | `refreshFromIhdRow(0, ...)` | 等价 |
|
||
| `get_pkeys(i)` / `get_tagkeys(i)` / `get_pvkeys(i, j)` | 内部 VarsCache(不暴露) | 封装 |
|
||
| `pre_init(tags)` (VarsCache 初始化) | 构造函数自动完成 | 简化 |
|
||
| 双 FunVars(ExpModule + ExpBase 各一套) | 统一 FunVars(ExpressionEngine 唯一管理) | 去冗余 |
|
||
| `is_exp_alg_` 补丁(跳过 ExpBase 调用者的 update) | 消除,ExpressionEngine 不依赖此标志 | 消除补丁 |
|
||
|
||
---
|
||
|
||
## 七、总结
|
||
|
||
### 7.1 功能等价性结论
|
||
|
||
| 算法类型 | 算法数量 | 等价性 | 差异说明 |
|
||
|----------|---------|--------|---------|
|
||
| LogicAlg (ExpType=1) | 1 | **等价** | alarm_value 从 bool 变为实际值(正向修复) |
|
||
| BoundAlg (ExpType=2) | 1 | **等价** | 无差异 |
|
||
| FeedbackAlg (ExpType=3/4) | 1 | **等价** | 7 状态 FSM 复现全部行为 |
|
||
| BoundHoldAlg (ExpType=5) | 1 | **等价** | 逐字照搬 |
|
||
| 其他 (ExpType=6~14) | 9 | **等价** | 仅机械 API 替换 |
|
||
|
||
**总计:14 种算法类型,全部功能等价,无行为退行。**
|
||
|
||
### 7.2 改动性质
|
||
|
||
整个重构是**纯结构变换**,不涉及业务逻辑重写:
|
||
|
||
1. **拆分**(Split):ExpBase 1956 行 → ExpBase 1105 行 + 4 个子类 329 行
|
||
2. **提取**(Extract):内联逻辑 → BoundChecker/StatCollector/FbStateMachine 独立类
|
||
3. **统一**(Unify):ExpModule + FunVars 双轨 → ExpressionEngine 单轨
|
||
4. **替换**(Replace):裸指针/标志 → 显式类型/枚举类
|
||
|
||
### 7.3 验证建议
|
||
|
||
1. **单元测试**:77 个测试全部通过,覆盖核心组件
|
||
2. **运行时验证**:eqpalg-mon 已在目标机器运行,无崩溃,有报警输出
|
||
3. **回归对比**:建议选取 2-3 条典型规则,对比重构前后报警记录(时间点、内容、级别)一致性
|
||
4. **持续观察**:关注日志中是否出现 `Unknown variable` 错误或 cron/task 进程异常
|
||
|
||
---
|
||
|
||
## 附录:重构涉及的全部文件
|
||
|
||
### 新增(14 个文件)
|
||
|
||
| 文件 | 说明 |
|
||
|------|------|
|
||
| `eqpalg/utility/expression_engine.h` | ExpressionEngine 头文件 |
|
||
| `eqpalg/utility/expression_engine.cpp` | ExpressionEngine 实现 |
|
||
| `eqpalg/utility/fb_state_machine.h` | FbStateMachine 头文件 |
|
||
| `eqpalg/utility/fb_state_machine.cpp` | FbStateMachine 实现 |
|
||
| `eqpalg/utility/bound_checker.h` | BoundChecker 头文件 |
|
||
| `eqpalg/utility/bound_checker.cpp` | BoundChecker 实现 |
|
||
| `eqpalg/utility/stat_collector.h` | StatCollector 头文件 |
|
||
| `eqpalg/utility/stat_collector.cpp` | StatCollector 实现 |
|
||
| `eqpalg/algs/logic_alg.h` | LogicAlg 头文件 |
|
||
| `eqpalg/algs/logic_alg.cpp` | LogicAlg 实现 |
|
||
| `eqpalg/algs/bound_alg.h` | BoundAlg 头文件 |
|
||
| `eqpalg/algs/bound_alg.cpp` | BoundAlg 实现 |
|
||
| `eqpalg/algs/bound_hold_alg.h` | BoundHoldAlg 头文件 |
|
||
| `eqpalg/algs/bound_hold_alg.cpp` | BoundHoldAlg 实现 |
|
||
| `eqpalg/algs/feedback_alg.h` | FeedbackAlg 头文件 |
|
||
| `eqpalg/algs/feedback_alg.cpp` | FeedbackAlg 实现 |
|
||
| `eqpalg/test/test_harness.h` | 测试框架 |
|
||
| `eqpalg/test/test_main.cc` | 测试入口 |
|
||
| `eqpalg/test/test_expression_engine.cc` | ExpressionEngine 测试(14 用例) |
|
||
| `eqpalg/test/test_fb_state_machine.cc` | FbStateMachine 测试(11 用例) |
|
||
| `eqpalg/test/test_algorithms.cc` | 算法集成测试(52 用例) |
|
||
|
||
### 删除(2 个文件)
|
||
|
||
| 文件 | 说明 |
|
||
|------|------|
|
||
| `eqpalg/utility/ExpModule.h` | 被 ExpressionEngine 替代 |
|
||
| `eqpalg/utility/ExpModule.cc` | 被 ExpressionEngine 替代 |
|
||
|
||
### 修改(27 个文件)
|
||
|
||
ExpBase、AlgBase、build_algorithm.cpp、CMakeLists.txt,以及 9 个算法子类的 .h/.cpp/.cc 文件。
|