ShadowVariableListener能否像ConstraintProvider一样访问集合属性?
首先明确说:ShadowVariableListener没办法直接像ConstraintProvider那样用查询API来访问这些集合——毕竟两者的设计定位不一样,ConstraintProvider是专门做约束匹配的工具,而ShadowVariableListener的核心职责是监听变量变化、同步计算影子变量。不过不用慌,有更合规的方式,完全不需要手动给对象加指针:
最推荐:通过ScoreDirector获取工作解,再提取集合
ShadowVariableListener的所有回调方法(比如afterVariableChanged)都会传入ScoreDirector实例,你可以通过它拿到当前的工作解(Working Solution),然后直接调用解对象的getter方法获取ProblemFactCollectionProperty或PlanningEntityCollectionProperty对应的集合。这完全符合OptaPlanner的设计逻辑,既不会增加代码耦合,还能保证拿到的是最新的工作状态。举个简单的代码示例:
@Override public void afterVariableChanged(ScoreDirector<MySolution> scoreDirector, Object entity) { // 从ScoreDirector拿到当前工作解 MySolution workingSolution = scoreDirector.getWorkingSolution(); // 获取问题事实集合 List<MyProblemFact> problemFacts = workingSolution.getMyProblemFactList(); // 获取规划实体集合 List<MyPlanningEntity> planningEntities = workingSolution.getMyPlanningEntityList(); // 接下来就可以用这些集合做你需要的约束相关计算了 }可选:初始化时缓存集合(谨慎使用)
如果你的Listener需要频繁访问这些集合,也可以在Listener的initialize方法里,从ScoreDirector拿到工作解并缓存集合引用。但要注意:如果工作解中的集合发生了动态更新(比如新增/删除问题事实),缓存的引用可能会失效,需要重新获取,否则会拿到旧数据。所以这种方式只适合集合不会动态变化的场景。不建议:手动添加指针
不要给每个带ShadowVariableListener的对象硬加指向这些集合的指针——这会大幅增加代码耦合,而且很容易出现状态不一致的问题(比如OptaPlanner切换了工作解,但你的指针还指向旧对象),后续维护起来会很头疼。
总结一下:优先用ScoreDirector + 工作解的方式来获取集合,这是最安全、最符合框架设计的做法。
内容的提问来源于stack exchange,提问作者Extenuate-Acronym-Bagged

