如何在TimeFold中基于RuleSetting动态选择约束类型
解决方案
要实现基于RuleSetting类型动态配置惩罚类型,你可以利用OptaPlanner ConstraintStream中penalize方法的重载版本——接受一个动态生成Score的函数,而非固定的Score常量。具体修改如下:
1. 直接内联类型映射逻辑(Java 12+ 推荐)
修改原代码中的penalize调用部分:
.penalize( // 动态根据RuleSetting类型返回对应的惩罚权重类型 (ruleSetting, employee, weekNo, noDays) -> switch(ruleSetting.getType()) { case "Hard" -> HardMediumSoftScore.ONE_HARD; case "Medium" -> HardMediumSoftScore.ONE_MEDIUM; case "Soft" -> HardMediumSoftScore.ONE_SOFT; default -> HardMediumSoftScore.ONE_SOFT; // 处理未知类型的默认值 }, (ruleSetting, employee, weekNo, noDays)->{ return (int)Math.abs(((double)ruleSetting.getWeight() * (double)noDays / (double) employee.getContracts().getMaxDaysPerWeek())); } )
2. 抽离映射逻辑为辅助方法(更易维护)
如果需要复用类型映射逻辑,可以在当前类中添加一个辅助方法:
private HardMediumSoftScore getPenaltyScoreType(String ruleType) { return switch(ruleType) { case "Hard" -> HardMediumSoftScore.ONE_HARD; case "Medium" -> HardMediumSoftScore.ONE_MEDIUM; case "Soft" -> HardMediumSoftScore.ONE_SOFT; default -> HardMediumSoftScore.ONE_SOFT; }; }
然后在penalize中调用该方法:
.penalize( (ruleSetting, employee, weekNo, noDays) -> getPenaltyScoreType(ruleSetting.getType()), (ruleSetting, employee, weekNo, noDays)->{ return (int)Math.abs(((double)ruleSetting.getWeight() * (double)noDays / (double) employee.getContracts().getMaxDaysPerWeek())); } )
3. Java 8/9 兼容版本(if-else实现)
如果你的项目使用较低版本的Java,无法使用switch表达式,可改用if-else:
.penalize( (ruleSetting, employee, weekNo, noDays) -> { String type = ruleSetting.getType(); if ("Hard".equals(type)) { return HardMediumSoftScore.ONE_HARD; } else if ("Medium".equals(type)) { return HardMediumSoftScore.ONE_MEDIUM; } else { return HardMediumSoftScore.ONE_SOFT; } }, (ruleSetting, employee, weekNo, noDays)->{ return (int)Math.abs(((double)ruleSetting.getWeight() * (double)noDays / (double) employee.getContracts().getMaxDaysPerWeek())); } )
方案说明
- 该方案利用
penalize方法的重载特性,针对每个匹配的规则+员工+周数组合,动态生成对应类型的惩罚Score,完全满足需求。 - 无需使用Configurable选项,直接通过代码逻辑实现动态配置,简洁高效。
- 增加了默认值处理,避免未知规则类型导致的异常。
内容的提问来源于stack exchange,提问作者I. Ahmed
相关产品推荐
相关产品推荐

