spring boot策略模式实用: 告警模块
0 涉及知识点
策略模式, 模板方法, 代理, 多态, 反射
1 需求概括
- 场景: 每隔一段时间, 会获取设备运行数据, 如通过温湿度计获取到当前环境温湿度;
- 需求: 对获取回来的进行分析, 超过配置的阈值需要产生对应的告警
2 方案设计
告警的类别往往容易变化, 比如今天只有温度过高告警, 明天可能就要增加一个温度过低告警, 所以设计最好可以满足开闭原则, 方便后续对功能进行删减;
整体思路如下:
- 顶层接口Handler定义了两个方法, check用于校验是否应该产告警, 入参可以选择传入告警配置和需要判定对象, handle方法主要用于告警的具体处理过程, 如之前是否存在告警等;
- 统一抽象类AbstractHandler中, 重写handle方法, 作为模版方法, 一般不同的告警处理流程是相近的, 可以抽象处理, 如都要判断进行判断当前是否已存在告警等; 抽象类中还可以抽象出通用的方法和声明通用属性;
- 各个具体实现类, 如TemperatureHandler等, 各类告警的具体实例对象, 如果告警判定方式或处理流程上有不同, 可以选择性的重写check方法或handle方法, 由于java的多态, 程序运行时会选择正确处理方式;
为了保证模块的完整性, 增加代理类屏蔽告警的内部处理逻辑, 外部统一通过代理类调用;
3 代码实现
-
接口
/** * 顶级接口 * @author lixiyuan */ public interface Handler { boolean check(AlarmConfig config, Object data); void handle(AlarmConfig config, Integer id, Object data); }
-
抽象类
/** * 抽象类, 抽取通用字段/方法, 实现模板方法 * @author lixiyuan */ public class AbstractHandler implements Handler { @Autowired private CurrentAlarmService currentAlarmService; @Override public boolean check(AlarmConfig config, Object data) { return false; } @Override public void handle(AlarmConfig config, Integer id, Object data) { // 获取当前存在的告警 CurrentAlarm current = currentAlarmService.getCurrentAlarmById(); // 比较阈值 boolean check = check(config, data); // 为true发生告警 if (check) { if (current == null) { // 创建告警 currentAlarmService.save(); } else { // 更新告警 currentAlarmService.update(); } } else { if (current != null) { // 结束告警 currentAlarmService.finish(); } } } /** * 反射获取属性值 */ protected String getValueByField(Object obj, String fieldName) { if (obj == null) { return ""; } try { Field field = obj.getClass().getDeclaredField(fieldName); field.setAccessible(true); Object value = field.get(obj); return value == null ? "" : value.toString(); } catch (NoSuchFieldException | IllegalAccessException e) { System.out.println(); throw new RuntimeException(e); } } /** * 如果判定方法比较通用, 也可以在这里定义好, 各个子类调用一下就行 */ protected boolean commonCompare() { return false; } }
-
实现子类
/** * * @author lixiyuan */ @Component public class HumidityHandler extends AbstractHandler { @Override public boolean check(AlarmConfig config, Object data) { // 通过反射获取实时数据 String humidity = getValueByField(data, "humidity"); // 拿到配置中的阈值,然后比较, 略 return false; } } /** * * @author lixiyuan */ @Component public class TemperatureHandler extends AbstractHandler { @Override public boolean check(AlarmConfig config, Object data) { // 通过反射获取实时数据 String humidity = getValueByField(data, "temperature"); // 拿到配置中的阈值,然后比较, 略 return false; } }
代码详见: [完成代码](nanqiangli/wushixian (github.com))