我有一个Lecture
类,startTime
规划变量和固定持续时间。我试图过滤掉导致结束时间超过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
中得到一个与不同规划变量相关的类强制转换异常。我试过添加variableName="startTime"
,但这会触发不同的类强制转换异常。
我是否在正确的轨道上,variableName
属性实际上是如何工作的?
我将从您的附加注释开始,您将进一步解释:
与
variableName="startTime"
我得到java.lang.ClassCastException: class package.ImmutableTimeslot cannot be cast to class package.Lecture
。没有variableName设置,我得到java.lang.ClassCastException: class package.Room cannot be cast to class package.Lecture
。
对于这种行为有一个解释,尽管它不是很直观:
- 当您将过滤器放在没有变量名的值选择器上时,两个变量类型都将到达过滤器。在本例中,
ImmutableTimeslot
和Room
。因为你的过滤器期望一个Lecture
,两者中的一个都会抛出异常。 - 当你指定选择器的变量名为
startTime
时,这将不再触发room
变量值的值选择器;因此,你得到一个异常,ImmutableTimeslot
不匹配Lecture
。
在这两种情况下,问题似乎是您的过滤器期望Lecture
实例(实体),但求解器正在发送ImmutableTimeslot
或Room
(规划变量的值)。这可以说是值选择器的正确行为(强调"value"这个词)。
我称它为"不太直观"的原因分为两部分:
- 始终需要相同的
SelectionFilter
接口,无论应用于移动选择器,实体选择器还是值选择器。因此,根据您打算使用它的地方,所需的泛型类型是不同的,这令人困惑。(一个移动,一个实体或一个值) - 在有多个变量的情况下(比如你的),没有在选择器上指定
variableName
,通用参数需要是Object
,因为过滤器将接收两种类型的值,这是避免异常的唯一方法。
总而言之,不是最好的设计;它从2012年开始,由于保持向后兼容性和我们实际上不鼓励使用选择过滤器,它一直保存到今天没有改变。