使用ValueSelector阻止特定移动时触发ClassCastException问题排查
OptaPlanner移动过滤器实现问题
问题背景
我有一个包含startTime规划变量和固定时长的Lecture类,想要过滤掉那些会导致结束时间超过16:00的移动操作。
编写的选择过滤器代码
public class LectureOutOfBoundsSelectionFilter implements SelectionFilter<Schedule, Lecture> { @Override public boolean accept(ScoreDirector<Schedule> sd, Lecture lecture) { return !lecture.isOutOfBounds(); } }
配置文件内容
<changeMoveSelector> <filterClass>package.PinnedTimeslotChangeMoveFilter</filterClass> <valueSelector> <filterClass>packager.LectureOutOfBoundsSelectionFilter</filterClass> </valueSelector> </changeMoveSelector>
遇到的异常
- 直接使用上述配置时,出现与
Lecture类中另一个规划变量相关的ClassCastException; - 尝试添加
variableName="startTime"属性后,触发了另一种类型转换异常。
疑问
- 我的实现思路是否正确?
variableName属性的实际作用是什么?
解答
1. 实现思路的问题
你的核心需求方向是对的,但过滤器的类型和使用位置选错了:
- 当前的
LectureOutOfBoundsSelectionFilter是用来过滤Lecture实体的,而你需要的是过滤会导致结束时间超标的移动操作(或对应的变量值); valueSelector中的过滤器应该针对startTime的变量值类型(比如Timeslot),而非Lecture实体本身,这是导致类型转换异常的直接原因。
更合适的方案是使用MoveFilter直接判断移动操作是否合法,或者调整valueSelector的过滤器为变量值类型的过滤器。
2. variableName的实际作用
当一个实体(比如Lecture)拥有多个规划变量时(比如startTime和room),variableName用来明确指定当前移动选择器操作的目标规划变量:
- 不指定该属性时,框架会默认处理实体的所有规划变量,导致你的过滤器被错误应用到其他变量的类型上,引发第一次的
ClassCastException; - 添加
variableName后,框架会聚焦到startTime变量,但你的过滤器仍然是针对Lecture实体的,和valueSelector需要的变量值类型不匹配,所以还是会触发类型转换异常。
修正方案
推荐使用MoveFilter直接过滤非法的移动操作,示例代码如下:
public class LectureMoveOutOfBoundsFilter implements MoveFilter<Schedule> { @Override public boolean accept(ScoreDirector<Schedule> scoreDirector, Move<Schedule> move) { // 只处理ChangeMove类型的操作 if (!(move instanceof ChangeMove)) { return true; } ChangeMove<Schedule> changeMove = (ChangeMove<Schedule>) move; Lecture lecture = (Lecture) changeMove.getEntity(); Timeslot newTimeslot = (Timeslot) changeMove.getValue(); // 计算结束时间并判断是否超过16:00 LocalTime endTime = newTimeslot.getStartTime().plusMinutes(lecture.getDuration()); return !endTime.isAfter(LocalTime.of(16, 0)); } }
对应的配置调整为:
<changeMoveSelector> <filterClass>package.LectureMoveOutOfBoundsFilter</filterClass> <variableName="startTime"/> </changeMoveSelector>
这样就能精准过滤掉所有会导致Lecture结束时间超过16:00的startTime变更操作。
内容的提问来源于stack exchange,提问作者aioobe
相关产品推荐
相关产品推荐

