You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Optaplanner/Timefold:如何动态获取初始化的SolutionCloner避免硬编码?

动态获取Optaplanner/Timefold的SolutionCloner

我有一个可正常运行的Optaplanner/Timefold解决方案,能为业务提供日间实时反馈。但变更请求会临时排队,因此我需要克隆当前最优解决方案,在将请求提交到主方案前测试其是否存在可行解。

目前我通过以下代码克隆解决方案:

SolutionDescriptor solutionDescriptor =  SolutionDescriptor.buildSolutionDescriptor(DistributionSolution.class, MoverEntity.class, LoaderEntity.class );
FieldAccessingSolutionCloner<DistributionSolution> distSolCloner = new FieldAccessingSolutionCloner<>(solutionDescriptor);
DistributionSolution clonedSolution =   distSolCloner.cloneSolution(currentDistributionSolution);

但硬编码解决方案和实体类的方式不够健壮,虽然可使用solverConfig.xml,但这仍是另一种硬编码,也可移至工厂类等。不过我希望找到更动态的方式获取初始化后的SolutionCloner。我注意到TimeFoldProcessor.class似乎通过反射实现了该功能,但不确定如何在运行时访问它?请问有什么解决思路吗?


解决思路

1. 从已初始化的Solver实例中提取SolutionDescriptor

如果你已经有运行中的Solver或SolverFactory实例,直接从中获取SolutionDescriptor是最直接的方案,完全复用已有配置,避免重复硬编码:

// 假设已初始化好SolverFactory
SolverFactory<DistributionSolution> solverFactory = ...;
SolutionDescriptor<DistributionSolution> solutionDescriptor = solverFactory.getSolverConfig().getSolutionDescriptor();
FieldAccessingSolutionCloner<DistributionSolution> cloner = new FieldAccessingSolutionCloner<>(solutionDescriptor);
DistributionSolution clonedSolution = cloner.cloneSolution(currentDistributionSolution);

2. 用反射工具类自动识别实体类

Timefold内置的ReflectionSolutionDescriptorFactory可以通过反射自动扫描解决方案类中的@PlanningEntityCollectionProperty注解,自动识别所有关联的实体类,无需显式指定:

// 仅传入解决方案类,自动解析实体类型
SolutionDescriptor<DistributionSolution> solutionDescriptor = ReflectionSolutionDescriptorFactory.buildSolutionDescriptor(DistributionSolution.class);
FieldAccessingSolutionCloner<DistributionSolution> cloner = new FieldAccessingSolutionCloner<>(solutionDescriptor);
DistributionSolution clonedSolution = cloner.cloneSolution(currentDistributionSolution);

3. 封装通用克隆工具类

如果需要在多处复用,可封装一个支持任意解决方案类型的工具类:

public class SolutionClonerUtil {
    @SuppressWarnings("unchecked")
    public static <T> T cloneSolution(T solution) {
        Class<T> solutionClass = (Class<T>) solution.getClass();
        SolutionDescriptor<T> solutionDescriptor = ReflectionSolutionDescriptorFactory.buildSolutionDescriptor(solutionClass);
        FieldAccessingSolutionCloner<T> cloner = new FieldAccessingSolutionCloner<>(solutionDescriptor);
        return cloner.cloneSolution(solution);
    }
}

使用时直接传入实例即可:

DistributionSolution clonedSolution = SolutionClonerUtil.cloneSolution(currentDistributionSolution);

关于TimeFoldProcessor的说明

TimeFoldProcessor是编译期注解处理器,作用是在编译时生成优化的克隆器、移动器等代码,而非运行时反射。如果想使用它生成的高效克隆器:

  1. 确保项目引入Timefold注解处理器依赖
  2. 解决方案类添加@PlanningSolution注解,实体类添加@PlanningEntity注解
  3. 编译后会自动生成{你的解决方案类名}Cloner类,运行时直接实例化使用:
// 编译生成的克隆器,性能比FieldAccessingSolutionCloner更高
DistributionSolutionCloner cloner = new DistributionSolutionCloner();
DistributionSolution clonedSolution = cloner.cloneSolution(currentDistributionSolution);

这种方式既避免硬编码,又能获得更优的克隆性能。


内容的提问来源于stack exchange,提问作者Christian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 12:25:12