javaer佬速来对我指指点点

先降低圈复杂度

1 Like

考虑解耦,业务判断预警和预警报警模块拆分,这里只判断是否预警,由预警报警模块单独判断是否重复预警,是否需要入库。这样后续万一要改报警判断逻辑或者发信息通知之类的会清晰一点。

能跑就是好代码:sunglasses:

献丑了,我觉得 @unique u佬的解题挺好的。我来水一个另一种思路。
1.利用map做简易策略模式封装,在bifunction里面处理对应的分支逻辑
2.利用数据库查询,减少对应代码判断过程
3.查询的数据必须做非空判断,以防npe
4.对于entry对象的封装和保存,建议封装成方法,提高可读性

对于这种多重判断的,我的经验是,如果你能把这些数据维度拉平,那最好做个策略模式,简单明了。如果不能,那么可能需要考虑分级,分组处理。

    private Map<String, BiFunction<DevicePollAlarmConfig, deviceData>> map = new HashMap() {{
        put("wd", (devicePollAlarmConfig, deviceData) -> {
            // do your work...
            /*
              1.alarmInfoMapper.selectAlarm(2, deviceData.getMn(), "wd");// 这里查询可以带上时间,可以减少代码里面的判断。其次查询出来的报警信息可能为空,需要做非空判断
              2.AlarmInfo实体类的处理,可以封装成方法,减少单个方法的行数,可读性更强
             */
        });
    }};
    public void newTest() {
        for (DevicePollAlarmConfig devicePollAlarmConfig : devicePollAlarmConfigs) {
            map.get(devicePollAlarmConfig.getPollCode());
        }
    }

2 Likes

太多if嵌套了,应该使用卫语句开发

List<CompletableFuture<Void>> futures = devicePollAlarmConfigs.stream()
        .map(devicePollAlarmConfig ->
                CompletableFuture.runAsync(() -> {
                    // 你的业务代码
                }, 你的线程池(必须设置不能用默认的)) 
        )
        .collect(Collectors.toList());
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

看變量命名應該0和2 是警報類型吧或者狀態吧

1.这么多if判断怎么去优化更优雅呢
也沒有太好的方法,抽離 if 中的執行邏輯為一個個函数、使用衛語句、提前跳出、合併判定條件、策略模式等等,但是需要衡量代碼可讀性,如果if 雖然多但是代碼可讀性好,我認為是沒必須要去優化的 寫好注釋和例子說明 這些if為啥要這些判定 才是重要的
2. 接收数据 处理数据 需要去多线程处理吗
首先有必要使用多線程嗎?接收和處理數據是否有前後關係?目前的處理對響應時間有影響?

@Component
public class DevicePollAlarmTask {

    private CompositePollCodeStrategy compositePollCodeStrategy;

    @Autowired
    public void setCompositePollCodeStrategy(CompositePollCodeStrategy compositePollCodeStrategy) {
        this.compositePollCodeStrategy = compositePollCodeStrategy;
    }

    private AlarmInfoMapper alarmInfoMapper;

    @Autowired
    public void setAlarmInfoMapper(AlarmInfoMapper alarmInfoMapper) {
        this.alarmInfoMapper = alarmInfoMapper;
    }

    public void execute(DeviceData deviceData) {
        List<DevicePollAlarmConfig> devicePollAlarmConfigs = alarmInfoMapper.selectAlarmConfigList();
        for (DevicePollAlarmConfig devicePollAlarmConfig : devicePollAlarmConfigs) {
            compositePollCodeStrategy.run(devicePollAlarmConfig, deviceData);
            List<AlarmInfo> notDealList = alarmInfoMapper.selectAlarmList(0);
            if (!notDealList.isEmpty()) {
                WebSocketServer.sendToOne("123", JsonUtil.toJson(notDealList));
            }
        }
    }
}


/**
 * PollCodeStrategy 是一个抽象类,定义了处理特定轮询代码策略的基础框架。
 * 它要求所有的具体策略实现两个核心方法:获取轮询代码的方法和执行策略的方法。
 * 这个类设计用于设备轮询报警的情景,其中每种轮询代码对应一种特定的处理策略。
 * <b>注意:</b>实现前请参考{@link  WDPollCodeStrategy}
 */
public abstract class PollCodeStrategy {

    /**
     * 获取当前策略的轮询代码。
     * 轮询代码是一个字符串标识符,用于区分不同的轮询策略。
     *
     * @return 轮询代码的字符串表示。
     */
    public abstract String getCode();

    /**
     * 执行策略的具体操作。
     * 此方法根据提供的设备轮询报警配置和设备数据执行策略逻辑。
     * 它由具体的策略实现类根据实际业务逻辑进行实现。
     *
     * @param devicePollAlarmConfig 设备轮询报警配置,包含轮询代码和相关阈值等配置信息。
     * @param deviceData            设备数据,包含当前轮询周期内从设备采集到的数据。
     */
    public abstract void run(DevicePollAlarmConfig devicePollAlarmConfig, DeviceData deviceData);
}


@Component
public class CompositePollCodeStrategy extends PollCodeStrategy {

    private Map<String, PollCodeStrategy> pollCodeStrategyMap;

    @Autowired
    public void setPollCodeStrategyMap(Map<String, PollCodeStrategy> pollCodeStrategyMap) {
        this.pollCodeStrategyMap = pollCodeStrategyMap;
    }

    @Override
    public void run(DevicePollAlarmConfig devicePollAlarmConfig, DeviceData deviceData) {
        String pollCode = devicePollAlarmConfig.getPollCode();
        PollCodeStrategy strategy = pollCodeStrategyMap.get(pollCode);
        if (strategy != null) {
            strategy.run(devicePollAlarmConfig, deviceData);
        } else {
            // 处理未找到匹配策略的情况
        }
    }

    @Override
    public String getCode() {
        // 由于这是组合策略,不需要实现此方法,默认返回Null
        return null;
    }
}

@Component("wd")
class WDPollCodeStrategy extends PollCodeStrategy {

    private final static String CODE = "wd";

    private AlarmInfoMapper alarmInfoMapper;

    @Autowired
    public void setAlarmInfoMapper(AlarmInfoMapper alarmInfoMapper) {
        this.alarmInfoMapper = alarmInfoMapper;
    }

    @Override
    public void run(DevicePollAlarmConfig devicePollAlarmConfig, DeviceData deviceData) {
        String tempFlag = deviceData.getTempFlag();
        String mn = deviceData.getMn();
        double lowerLimit = devicePollAlarmConfig.getLowerLimit();
        double upperLimit = devicePollAlarmConfig.getUpperLimit();
        double currentTemp = Double.parseDouble(deviceData.getTemp());
        // 从目前代码来看 似乎后续用不到 那返回一个数字 是否可以
        AlarmInfo checkAlarmInfo;
        if (
                Objects.equals("N", tempFlag)
                && (currentTemp > upperLimit || currentTemp < lowerLimit)
                && (checkAlarmInfo = alarmInfoMapper.selectAlarm(0, mn, code)) == null
        ) {
            AlarmInfo dealAlarm = alarmInfoMapper.selectAlarm(2, mn, code);
            // 存在已处理的同类型报警 且处理时间在5分钟内 不再报警
            if (dealAlarm != null) {
                if (LocalDateTime.now().minusMinutes(5).isBefore(dealAlarm.getUpdateTime())) {
                    return;
                }
                dealAlarm.setIsDeal(1);
                alarmInfoMapper.updateById(dealAlarm);
            }
            // 可以抽离到一个函数
            AlarmInfo alarmInfo = new AlarmInfo();
            alarmInfo.setMn(mn);
            alarmInfo.setDeviceName("恒温系统");
            alarmInfo.setAlarmContent("温度超限" + currentTemp + "℃" + "(阈值" + lowerLimit + "℃~" + upperLimit + "℃)");
            alarmInfo.setAlarmType(2);
            alarmInfo.setAlarmCode(code);
            alarmInfoMapper.insert(alarmInfo);
        }
    }

    @Override
    public String getCode() {
        return CODE;
    }
}

@Component("sd")
class SDPollCodeStrategy extends PollCodeStrategy {

    private final static String CODE= "sd";

    private AlarmInfoMapper alarmInfoMapper;

    @Autowired
    public void setAlarmInfoMapper(AlarmInfoMapper alarmInfoMapper) {
        this.alarmInfoMapper = alarmInfoMapper;
    }

    @Override
    public void run(DevicePollAlarmConfig devicePollAlarmConfig, DeviceData deviceData) {
        if (Objects.equals("N", deviceData.getHumidityFlag())) {
            // do something
        }
    }

    @Override
    public String getCode() {
        return CODE;
    }
}

报警吧